minix/minix/lib/libsffs/stat.c
David van Moolenbroek 22840dea11 libfsdriver: preinitialize stat.st_ino
The stat.st_ino field must always be filled with the inode number
given as part of the fdr_stat request anyway, so libfsdriver can
simply fill in the number and allow the file system not to bother.

Change-Id: Ia7a849d0b23dfc83010df0d48fa26e4225427694
2015-06-23 14:38:04 +00:00

177 lines
4.4 KiB
C

/* 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 *
*===========================================================================*/
mode_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 (read_only)
mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
return mode;
}
/*===========================================================================*
* do_stat *
*===========================================================================*/
int do_stat(ino_t ino_nr, struct stat *stat)
{
/* Retrieve inode status.
*/
struct inode *ino;
struct sffs_attr attr;
char path[PATH_MAX];
int r;
/* 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;
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 OK;
}
/*===========================================================================*
* do_chmod *
*===========================================================================*/
int do_chmod(ino_t ino_nr, mode_t *mode)
{
/* Change file mode.
*/
struct inode *ino;
char path[PATH_MAX];
struct sffs_attr attr;
int r;
if (read_only)
return EROFS;
if ((ino = find_inode(ino_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 = *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;
*mode = get_mode(ino, attr.a_mode);
return OK;
}
/*===========================================================================*
* do_utime *
*===========================================================================*/
int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
{
/* Set file times.
*/
struct inode *ino;
char path[PATH_MAX];
struct sffs_attr attr;
int r;
if (read_only)
return EROFS;
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if ((r = verify_inode(ino, path, NULL)) != OK)
return r;
attr.a_mask = 0;
switch (atime->tv_nsec) {
case UTIME_OMIT: /* do not touch */
break;
case UTIME_NOW:
/* XXX VFS should have time() into ACTIME, for compat; we trust it! */
atime->tv_nsec = 0;
/*FALLTHROUGH*/
default:
attr.a_atime = *atime;
attr.a_mask |= SFFS_ATTR_ATIME;
break;
}
switch (mtime->tv_nsec) {
case UTIME_OMIT: /* do not touch */
break;
case UTIME_NOW:
/* XXX VFS should have time() into MODTIME, for compat; we trust it! */
mtime->tv_nsec = 0;
/*FALLTHROUGH*/
default:
attr.a_mtime = *mtime;
attr.a_mask |= SFFS_ATTR_MTIME;
break;
}
return sffs_table->t_setattr(path, &attr);
}