/*===========================================================================* * fs_putnode * *===========================================================================*/ PUBLIC int fs_putnode() { /* Find the inode specified by the request message and decrease its counter. */ int count; struct dir_record *dir = NULL; dir = get_dir_record(fs_m_in.REQ_INODE_NR); release_dir_record(dir); count = fs_m_in.REQ_COUNT; if (count <= 0) return(EINVAL); if (count > dir->d_count) { printf("put_inode: count too high: %d > %d\n", count, dir->d_count); return(EINVAL); } if (dir->d_count > 1) dir->d_count = dir->d_count - count + 1;/*Keep at least one reference*/ release_dir_record(dir); /* Actual inode release, might be last reference */ return(OK); }
/*===========================================================================* * fs_mountpoint * *===========================================================================*/ PUBLIC int fs_mountpoint() { /* This function looks up the mount point, it checks the condition whether * the partition can be mounted on the inode or not. */ register struct dir_record *rip; int r = OK; /* Temporarily open the file. */ if ((rip = get_dir_record(fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); if (rip->d_mountpoint) r = EBUSY; /* If the inode is not a dir returns error */ if ((rip->d_mode & I_TYPE) != I_DIRECTORY) r = ENOTDIR; release_dir_record(rip); if (r == OK) rip->d_mountpoint = TRUE; return(r); }
/*===========================================================================* * fs_putnode * *===========================================================================*/ PUBLIC int fs_putnode() { /* Find the inode specified by the request message and decrease its counter. */ int count; struct dir_record *dir = (void *)0; /* if (fs_m_in.REQ_INODE_INDEX >= 0 && */ /* fs_m_in.REQ_INODE_INDEX <= NR_DIR_RECORDS && */ /* ID_DIR_RECORD((dir_records + fs_m_in.REQ_INODE_INDEX)) == fs_m_in.REQ_INODE_NR) { */ /* dir = &dir_records[fs_m_in.REQ_INODE_INDEX]; */ /* /\* In this case the dir record by the dir record table *\/ */ /* } else { */ dir = get_dir_record(fs_m_in.REQ_INODE_NR); /* Get dir record increased the counter. We must decrease it releasing * it */ release_dir_record(dir); if (dir == (void *)0) { panic(__FILE__, "fs_putnode failed", NO_NUM); } count= fs_m_in.REQ_COUNT; /* I will check that the values of the count * are the same */ if (count <= 0) { printf("put_inode: bad value for count: %d\n", count); panic(__FILE__, "fs_putnode failed", NO_NUM); return EINVAL; } if (count > dir->d_count) { printf("put_inode: count too high: %d > %d\n", count, dir->d_count); panic(__FILE__, "fs_putnode failed", NO_NUM); return EINVAL; } if (dir->d_count > 1) dir->d_count = dir->d_count - count + 1; /* If the dir record should be released this operation will bring the counter to 1. The next function will further decreases it releasing it completely. */ release_dir_record(dir); /* I finally release it */ return OK; }
/*===========================================================================* * fs_read * *===========================================================================*/ int fs_read(void) { int r, chunk, block_size; int nrbytes; cp_grant_id_t gid; off_t position, f_size, bytes_left; unsigned int off, cum_io; int completed; struct dir_record *dir; r = OK; /* Try to get inode according to its index */ dir = get_dir_record(fs_m_in.REQ_INODE_NR); if (dir == NULL) return(EINVAL); /* no inode found */ position = fs_m_in.REQ_SEEK_POS_LO; nrbytes = (unsigned) fs_m_in.REQ_NBYTES; /* number of bytes to read */ block_size = v_pri.logical_block_size_l; gid = fs_m_in.REQ_GRANT; f_size = dir->d_file_size; rdwt_err = OK; /* set to EIO if disk error occurs */ cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes != 0) { off = (unsigned int) (position % block_size); chunk = MIN(nrbytes, block_size - off); if (chunk < 0) chunk = block_size - off; bytes_left = f_size - position; if (position >= f_size) break; /* we are beyond EOF */ if (chunk > bytes_left) chunk = (int) bytes_left; /* Read or write 'chunk' bytes. */ r = read_chunk(dir, cvul64(position), off, chunk, (unsigned) nrbytes, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += chunk; /* position within the file */ } fs_m_out.RES_SEEK_POS_LO = position; if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; fs_m_out.RES_NBYTES = cum_io; /*dir->d_file_size;*/ release_dir_record(dir); return(r); }
/*===========================================================================* * fs_access * *===========================================================================*/ int fs_access() { struct dir_record *rip; int r = OK; /* Temporarily open the file whose access is to be checked. */ caller_uid = fs_m_in.REQ_UID; caller_gid = fs_m_in.REQ_GID; /* Temporarily open the file. */ if ( (rip = get_dir_record(fs_m_in.REQ_INODE_NR)) == NULL) { printf("ISOFS(%d) get_dir_record by fs_access() failed\n", SELF_E); return(EINVAL); } /* For now ISO9660 doesn't have permission control (read and execution to * everybody by default. So the access is always granted. */ release_dir_record(rip); /* Release the dir record used */ return(r); }
/*===========================================================================* * fs_getdents * *===========================================================================*/ int fs_getdents(void) { struct dir_record *dir; ino_t ino; cp_grant_id_t gid; size_t block_size; off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off; struct buf *bp; struct dir_record *dir_tmp; struct dirent *dirp; int r,done,o,len,reclen; char *cp; char name[NAME_MAX + 1]; char name_old[NAME_MAX + 1]; /* Initialize the tmp arrays */ memset(name,'\0',NAME_MAX); memset(name_old,'\0',NAME_MAX); /* Get input parameters */ ino = fs_m_in.REQ_INODE_NR; gid = fs_m_in.REQ_GRANT; pos = fs_m_in.REQ_SEEK_POS_LO; block_size = v_pri.logical_block_size_l; cur_pos = pos; /* The current position */ tmpbuf_offset = 0; userbuf_off = 0; memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ if ((dir = get_dir_record(ino)) == NULL) return(EINVAL); block = dir->loc_extent_l; /* First block of the directory */ block += pos / block_size; /* Shift to the block where start to read */ done = FALSE; while (cur_pos<dir->d_file_size) { bp = get_block(block); /* Get physical block */ if (bp == NULL) { release_dir_record(dir); return(EINVAL); } block_pos = cur_pos % block_size; /* Position where to start read */ while (block_pos < block_size) { dir_tmp = get_free_dir_record(); create_dir_record(dir_tmp,bp->b_data + block_pos, block*block_size + block_pos); if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */ block_pos = block_size; done = TRUE; release_dir_record(dir_tmp); } else { /* The dir record is valid. Copy data... */ if (dir_tmp->file_id[0] == 0) strlcpy(name, ".", NAME_MAX + 1); else if (dir_tmp->file_id[0] == 1) strlcpy(name, "..", NAME_MAX + 1); else { /* Extract the name from the field file_id */ strncpy(name, dir_tmp->file_id, dir_tmp->length_file_id); name[dir_tmp->length_file_id] = 0; /* Tidy up file name */ cp = memchr(name, ';', NAME_MAX); if (cp != NULL) name[cp - name] = 0; /*If no file extension, then remove final '.'*/ if (name[strlen(name) - 1] == '.') name[strlen(name) - 1] = '\0'; } if (strcmp(name_old, name) == 0) { cur_pos += dir_tmp->length; release_dir_record(dir_tmp); continue; } strlcpy(name_old, name, NAME_MAX + 1); /* Compute the length of the name */ cp = memchr(name, '\0', NAME_MAX); if (cp == NULL) len = NAME_MAX; else len= cp - name; /* Compute record length */ reclen = offsetof(struct dirent, d_name) + len + 1; o = (reclen % sizeof(long)); if (o != 0) reclen += sizeof(long) - o; /* If the new record does not fit, then copy the buffer * and start from the beginning. */ if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) { r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, (vir_bytes)getdents_buf, tmpbuf_offset); if (r != OK) panic("fs_getdents: sys_safecopyto failed: %d", r); userbuf_off += tmpbuf_offset; tmpbuf_offset= 0; } /* The standard data structure is created using the * data in the buffer. */ dirp = (struct dirent *) &getdents_buf[tmpbuf_offset]; dirp->d_ino = (ino_t)(bp->b_data + block_pos); dirp->d_off= cur_pos; dirp->d_reclen= reclen; memcpy(dirp->d_name, name, len); dirp->d_name[len]= '\0'; tmpbuf_offset += reclen; cur_pos += dir_tmp->length; release_dir_record(dir_tmp); } block_pos += dir_tmp->length; } put_block(bp); /* release the block */ if (done == TRUE) break; cur_pos += block_size - cur_pos; block++; /* read the next one */ } if (tmpbuf_offset != 0) { r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, (vir_bytes) getdents_buf, tmpbuf_offset); if (r != OK) panic("fs_getdents: sys_safecopyto failed: %d", r); userbuf_off += tmpbuf_offset; } fs_m_out.RES_NBYTES = userbuf_off; fs_m_out.RES_SEEK_POS_LO = cur_pos; release_dir_record(dir); /* release the inode */ return(OK); }