/* This file contains file metadata retrieval and manipulation routines. * * The entry points into this file are: * get_mode return a file's mode * do_stat perform the STAT file system call * do_chmod perform the CHMOD file system call * do_utime perform the UTIME file system call * * Created: * April 2009 (D.C. van Moolenbroek) */ #include "inc.h" /*===========================================================================* * get_mode * *===========================================================================*/ pmode_t get_mode(struct inode *ino, int mode) { /* Return the mode for an inode, given the inode and the retrieved mode. */ mode &= S_IRWXU; mode = mode | (mode >> 3) | (mode >> 6); if (IS_DIR(ino)) mode = S_IFDIR | (mode & sffs_params->p_dir_mask); else mode = S_IFREG | (mode & sffs_params->p_file_mask); if (state.s_read_only) mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); return mode; } /*===========================================================================* * do_stat * *===========================================================================*/ int do_stat(void) { /* Retrieve inode status. */ struct inode *ino; struct sffs_attr attr; struct stat stat; char path[PATH_MAX]; pino_t ino_nr; int r; ino_nr = m_in.REQ_INODE_NR; /* Don't increase the inode refcount: it's already open anyway */ if ((ino = find_inode(ino_nr)) == NULL) return EINVAL; attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE | SFFS_ATTR_CRTIME | SFFS_ATTR_ATIME | SFFS_ATTR_MTIME | SFFS_ATTR_CTIME; if ((r = verify_inode(ino, path, &attr)) != OK) return r; memset(&stat, 0, sizeof(struct stat)); stat.st_dev = state.s_dev; stat.st_ino = ino_nr; stat.st_mode = get_mode(ino, attr.a_mode); stat.st_uid = sffs_params->p_uid; stat.st_gid = sffs_params->p_gid; stat.st_rdev = NO_DEV; stat.st_size = attr.a_size; stat.st_atimespec = attr.a_atime; stat.st_mtimespec = attr.a_mtime; stat.st_ctimespec = attr.a_ctime; stat.st_birthtimespec = attr.a_crtime; stat.st_blocks = stat.st_size / S_BLKSIZE; if (stat.st_size % S_BLKSIZE != 0) stat.st_blocks += 1; stat.st_blksize = BLOCK_SIZE; /* We could make this more accurate by iterating over directory inodes' * children, counting how many of those are directories as well. * It's just not worth it. */ stat.st_nlink = 0; if (ino->i_parent != NULL) stat.st_nlink++; if (IS_DIR(ino)) { stat.st_nlink++; if (HAS_CHILDREN(ino)) stat.st_nlink++; } return sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, 0, (vir_bytes) &stat, sizeof(stat)); } /*===========================================================================* * do_chmod * *===========================================================================*/ int do_chmod(void) { /* Change file mode. */ struct inode *ino; char path[PATH_MAX]; struct sffs_attr attr; int r; if (state.s_read_only) return EROFS; if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if ((r = verify_inode(ino, path, NULL)) != OK) return r; /* Set the new file mode. */ attr.a_mask = SFFS_ATTR_MODE; attr.a_mode = m_in.REQ_MODE; /* no need to convert in this direction */ if ((r = sffs_table->t_setattr(path, &attr)) != OK) return r; /* We have no idea what really happened. Query for the mode again. */ if ((r = verify_path(path, ino, &attr, NULL)) != OK) return r; m_out.RES_MODE = get_mode(ino, attr.a_mode); return OK; } /*===========================================================================* * do_utime * *===========================================================================*/ int do_utime(void) { /* Set file times. */ struct inode *ino; char path[PATH_MAX]; struct sffs_attr attr; int r; if (state.s_read_only) return EROFS; if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if ((r = verify_inode(ino, path, NULL)) != OK) return r; attr.a_mask = 0; switch(m_in.REQ_ACNSEC) { case UTIME_OMIT: /* do not touch */ break; case UTIME_NOW: /* XXX VFS should have time() into ACTIME, for compat; we trust it! */ m_in.REQ_ACNSEC = 0; /*FALLTHROUGH*/ default: /* cases m_in.REQ_ACNSEC < 0 || m_in.REQ_ACNSEC >= 1E9 * are caught by VFS to cooperate with old instances of EXT2 */ attr.a_atime.tv_sec = m_in.REQ_ACTIME; attr.a_atime.tv_nsec = m_in.REQ_ACNSEC; attr.a_mask |= SFFS_ATTR_ATIME; break; } switch(m_in.REQ_MODNSEC) { case UTIME_OMIT: /* do not touch */ break; case UTIME_NOW: /* XXX VFS should have time() into MODTIME, for compat; we trust it! */ m_in.REQ_MODNSEC = 0; /*FALLTHROUGH*/ default: /* cases m_in.REQ_MODNSEC < 0 || m_in.REQ_MODNSEC >= 1E9 * are caught by VFS to cooperate with old instances */ attr.a_mtime.tv_sec = m_in.REQ_MODTIME; attr.a_mtime.tv_nsec = m_in.REQ_MODNSEC; attr.a_mask |= SFFS_ATTR_MTIME; break; } return sffs_table->t_setattr(path, &attr); }