/*===========================================================================* * fs_getdents * *===========================================================================*/ PUBLIC int fs_getdents(void) { int r; register struct puffs_node *pn; ino_t ino; cp_grant_id_t gid; size_t size, buf_left; off_t pos; struct dirent *dent; int eofflag = 0; size_t written; PUFFS_MAKECRED(pcr, &global_kcred); ino = (ino_t) fs_m_in.REQ_INODE_NR; gid = (gid_t) fs_m_in.REQ_GRANT; size = buf_left = (size_t) fs_m_in.REQ_MEM_SIZE; pos = (off_t) fs_m_in.REQ_SEEK_POS_LO; if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino)) == NULL) { lpuffs_debug("walk failed...\n"); return(EINVAL); } if (GETDENTS_BUFSIZ < size) size = buf_left = GETDENTS_BUFSIZ; memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ dent = (struct dirent*) getdents_buf; r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, &pos, &buf_left, pcr, &eofflag, 0, 0); if (r) { lpuffs_debug("puffs_node_readdir returned error\n"); return(EINVAL); } assert(buf_left <= size); written = size - buf_left; if (written == 0 && !eofflag) { lpuffs_debug("The user's buffer is too small\n"); return(EINVAL); } if (written) { r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0, (vir_bytes) getdents_buf, written, D); if (r != OK) return(r); } update_times(pn, ATIME, 0); fs_m_out.RES_NBYTES = written; fs_m_out.RES_SEEK_POS_LO = pos; return(OK); }
/*===========================================================================* * fs_stat * *===========================================================================*/ int fs_stat() { register int r; /* return value */ register struct puffs_node *pn; /* target pnode */ struct vattr va; struct stat statbuf; mode_t mo; int s; PUFFS_MAKECRED(pcr, &global_kcred); if (global_pu->pu_ops.puffs_node_getattr == NULL) { lpuffs_debug("fs_stat: puffs_node_getattr is missing\n"); return(EINVAL); } if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL) { lpuffs_debug("walk failed...\n"); return(EINVAL); } if (global_pu->pu_ops.puffs_node_getattr(global_pu, pn, &va, pcr) != 0) { if (errno) { if (errno > 0) errno = -errno; return(errno); } return(EINVAL); } /* Fill in the statbuf struct. */ mo = va.va_mode & I_TYPE; /* true iff special */ s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); statbuf.st_dev = fs_dev; statbuf.st_ino = va.va_fileid; statbuf.st_mode = va.va_mode; statbuf.st_nlink = va.va_nlink; statbuf.st_uid = va.va_uid; statbuf.st_gid = va.va_gid; statbuf.st_rdev = (s ? va.va_rdev : NO_DEV); statbuf.st_size = va.va_size; statbuf.st_atime = va.va_atime.tv_sec; statbuf.st_mtime = va.va_mtime.tv_sec; statbuf.st_ctime = va.va_ctime.tv_sec; /* Copy the struct to user space. */ r = sys_safecopyto(fs_m_in.m_source, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) &statbuf, (size_t) sizeof(statbuf)); return(r); }
/*===========================================================================* * fs_stat * *===========================================================================*/ int fs_stat(ino_t ino_nr, struct stat *statbuf) { register struct puffs_node *pn; /* target pnode */ struct vattr va; mode_t mo; int s; PUFFS_MAKECRED(pcr, &global_kcred); if (global_pu->pu_ops.puffs_node_getattr == NULL) { lpuffs_debug("fs_stat: puffs_node_getattr is missing\n"); return(EINVAL); } if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) { lpuffs_debug("walk failed...\n"); return(EINVAL); } if (global_pu->pu_ops.puffs_node_getattr(global_pu, pn, &va, pcr) != 0) { if (errno) { if (errno > 0) errno = -errno; return(errno); } return(EINVAL); } /* Fill in the statbuf struct. */ mo = va.va_mode & I_TYPE; /* true iff special */ s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); statbuf->st_ino = va.va_fileid; statbuf->st_mode = va.va_mode; statbuf->st_nlink = va.va_nlink; statbuf->st_uid = va.va_uid; statbuf->st_gid = va.va_gid; statbuf->st_rdev = (s ? va.va_rdev : NO_DEV); statbuf->st_size = va.va_size; statbuf->st_atimespec = va.va_atime; statbuf->st_mtimespec = va.va_mtime; statbuf->st_ctimespec = va.va_ctime; statbuf->st_birthtimespec = va.va_birthtime; statbuf->st_blksize = va.va_blocksize; statbuf->st_blocks = va.va_bytes / va.va_blocksize; statbuf->st_flags = va.va_flags; statbuf->st_gen = va.va_gen; return(OK); }
/*===========================================================================* * fs_statvfs * *===========================================================================*/ int fs_statvfs(struct statvfs *st) { if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, st) != 0) { lpuffs_debug("statvfs failed\n"); return(EINVAL); } /* libpuffs doesn't truncate filenames */ st->f_flag |= ST_NOTRUNC; return(OK); }
/*===========================================================================* * fs_sync * *===========================================================================*/ int fs_sync() { /* Perform the sync() system call. Flush all the tables. * The order in which the various tables are flushed is critical. */ int r; PUFFS_MAKECRED(pcr, &global_kcred); if (is_readonly_fs) return(OK); /* nothing to sync */ r = global_pu->pu_ops.puffs_fs_sync(global_pu, MNT_WAIT, pcr); if (r) { lpuffs_debug("Warning: sync failed!\n"); } return(OK); /* sync() can't fail */ }
/*===========================================================================* * fs_fstatfs * *===========================================================================*/ int fs_fstatfs() { int r; struct statvfs st_vfs; struct statfs st; if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, &st_vfs) != 0) { lpuffs_debug("statfs failed\n"); return(EINVAL); } st.f_bsize = st_vfs.f_bsize; /* Copy the struct to user space. */ r = sys_safecopyto(fs_m_in.m_source, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) &st, (size_t) sizeof(st)); return(r); }
/*===========================================================================* * fs_statvfs * *===========================================================================*/ int fs_statvfs() { int r; struct statvfs st; if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, &st) != 0) { lpuffs_debug("statvfs failed\n"); return(EINVAL); } /* XXX libpuffs doesn't truncate filenames and returns ENAMETOOLONG, * though some servers would like to behave differently. * See subtest 2.18-19 of test23 and test/common.c:does_fs_truncate(). */ st.f_flag |= ST_NOTRUNC; /* Copy the struct to user space. */ r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0, (vir_bytes) &st, (phys_bytes) sizeof(st)); return(r); }
/*===========================================================================* * fs_readwrite * *===========================================================================*/ PUBLIC int fs_readwrite(void) { int r = OK, rw_flag; cp_grant_id_t gid; off_t pos; size_t nrbytes, bytes_left, bytes_done; struct puffs_node *pn; struct vattr va; PUFFS_MAKECRED(pcr, &global_kcred); if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL) { lpuffs_debug("walk failed...\n"); return(EINVAL); } /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; pos = (off_t) fs_m_in.REQ_SEEK_POS_LO; nrbytes = bytes_left = (size_t) fs_m_in.REQ_NBYTES; if (nrbytes > RW_BUFSIZ) nrbytes = bytes_left = RW_BUFSIZ; memset(getdents_buf, '\0', RW_BUFSIZ); /* Avoid leaking any data */ if (rw_flag == READING) { if (global_pu->pu_ops.puffs_node_read == NULL) return(EINVAL); r = global_pu->pu_ops.puffs_node_read(global_pu, pn, (uint8_t *)rw_buf, pos, &bytes_left, pcr, 0); if (r) { lpuffs_debug("puffs_node_read failed\n"); return(EINVAL); } bytes_done = nrbytes - bytes_left; if (bytes_done) { r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0, (vir_bytes) rw_buf, bytes_done, D); update_times(pn, ATIME, 0); } } else if (rw_flag == WRITING) { /* At first try to change vattr */ if (global_pu->pu_ops.puffs_node_setattr == NULL) return(EINVAL); puffs_vattr_null(&va); if ( (pos + bytes_left) > pn->pn_va.va_size) va.va_size = bytes_left + pos; va.va_ctime.tv_sec = va.va_mtime.tv_sec = clock_time(); va.va_atime.tv_sec = pn->pn_va.va_atime.tv_sec; r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr); if (r) return(EINVAL); r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) 0, (vir_bytes) rw_buf, nrbytes, D); if (r != OK) return(EINVAL); if (global_pu->pu_ops.puffs_node_write == NULL) return(EINVAL); r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf, pos, &bytes_left, pcr, 0); bytes_done = nrbytes - bytes_left; } if (r != OK) return(EINVAL); fs_m_out.RES_SEEK_POS_LO = pos + bytes_done; fs_m_out.RES_NBYTES = bytes_done; return(r); }