2010-01-26 00:18:02 +01:00
|
|
|
/* 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 *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC mode_t get_mode(ino, mode)
|
|
|
|
struct inode *ino;
|
|
|
|
int mode;
|
|
|
|
{
|
|
|
|
/* Return the mode for an inode, given the inode and the HGFS retrieved mode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
mode &= S_IRWXU;
|
|
|
|
mode = mode | (mode >> 3) | (mode >> 6);
|
|
|
|
|
|
|
|
if (IS_DIR(ino))
|
|
|
|
mode = S_IFDIR | (mode & opt.dir_mask);
|
|
|
|
else
|
|
|
|
mode = S_IFREG | (mode & opt.file_mask);
|
|
|
|
|
|
|
|
if (state.read_only)
|
|
|
|
mode &= ~0222;
|
|
|
|
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_stat *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_stat()
|
|
|
|
{
|
2010-08-07 13:50:15 +02:00
|
|
|
/* Retrieve inode status.
|
2010-01-26 00:18:02 +01:00
|
|
|
*/
|
|
|
|
struct inode *ino;
|
|
|
|
struct hgfs_attr attr;
|
|
|
|
struct stat stat;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
ino_t ino_nr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
ino_nr = m_in.REQ_INODE_NR;
|
|
|
|
|
|
|
|
/* Don't increase the inode refcount: it's already open anyway */
|
2010-05-10 15:26:00 +02:00
|
|
|
if ((ino = find_inode(ino_nr)) == NULL)
|
2010-01-26 00:18:02 +01:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE | HGFS_ATTR_ATIME |
|
|
|
|
HGFS_ATTR_MTIME | HGFS_ATTR_CTIME;
|
|
|
|
|
|
|
|
if ((r = verify_inode(ino, path, &attr)) != OK)
|
|
|
|
return r;
|
|
|
|
|
2011-07-01 21:35:54 +02:00
|
|
|
memset(&stat, 0, sizeof(struct stat));
|
|
|
|
|
2010-01-26 00:18:02 +01:00
|
|
|
stat.st_dev = state.dev;
|
|
|
|
stat.st_ino = ino_nr;
|
|
|
|
stat.st_mode = get_mode(ino, attr.a_mode);
|
|
|
|
stat.st_uid = opt.uid;
|
|
|
|
stat.st_gid = opt.gid;
|
|
|
|
stat.st_rdev = NO_DEV;
|
2010-09-27 15:19:25 +02:00
|
|
|
if (cmp64u(attr.a_size, LONG_MAX) > 0)
|
|
|
|
stat.st_size = LONG_MAX;
|
|
|
|
else
|
|
|
|
stat.st_size = ex64lo(attr.a_size);
|
2010-01-26 00:18:02 +01:00
|
|
|
stat.st_atime = attr.a_atime;
|
|
|
|
stat.st_mtime = attr.a_mtime;
|
|
|
|
stat.st_ctime = attr.a_ctime;
|
|
|
|
|
2011-07-01 21:35:54 +02:00
|
|
|
stat.st_blocks = stat.st_size / S_BLKSIZE;
|
|
|
|
if (stat.st_size % S_BLKSIZE != 0)
|
|
|
|
stat.st_blocks += 1;
|
|
|
|
|
|
|
|
stat.st_blksize = BLOCK_SIZE;
|
|
|
|
|
2010-01-26 00:18:02 +01:00
|
|
|
/* 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;
|
2010-05-10 15:26:00 +02:00
|
|
|
if (ino->i_parent != NULL) stat.st_nlink++;
|
2010-01-26 00:18:02 +01:00
|
|
|
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), D);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_chmod *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_chmod()
|
|
|
|
{
|
|
|
|
/* Change file mode.
|
|
|
|
*/
|
|
|
|
struct inode *ino;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
struct hgfs_attr attr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (state.read_only)
|
|
|
|
return EROFS;
|
|
|
|
|
2010-05-10 15:26:00 +02:00
|
|
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
2010-01-26 00:18:02 +01:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((r = verify_inode(ino, path, NULL)) != OK)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* Set the new file mode. */
|
|
|
|
attr.a_mask = HGFS_ATTR_MODE;
|
|
|
|
attr.a_mode = m_in.REQ_MODE; /* no need to convert in this direction */
|
|
|
|
|
|
|
|
if ((r = hgfs_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 *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_utime()
|
|
|
|
{
|
|
|
|
/* Set file times.
|
|
|
|
*/
|
|
|
|
struct inode *ino;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
struct hgfs_attr attr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (state.read_only)
|
|
|
|
return EROFS;
|
|
|
|
|
2010-05-10 15:26:00 +02:00
|
|
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
2010-01-26 00:18:02 +01:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((r = verify_inode(ino, path, NULL)) != OK)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
attr.a_mask = HGFS_ATTR_ATIME | HGFS_ATTR_MTIME;
|
|
|
|
attr.a_atime = m_in.REQ_ACTIME;
|
|
|
|
attr.a_mtime = m_in.REQ_MODTIME;
|
|
|
|
|
|
|
|
return hgfs_setattr(path, &attr);
|
|
|
|
}
|