/**************************************************************************** * fs/vfs/fs_fchstat.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include "inode/inode.h" /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: fchstat ****************************************************************************/ static int fchstat(int fd, FAR struct stat *buf, int flags) { FAR struct file *filep; int ret; /* First, get the file structure. Note that on failure, * fs_getfilep() will return the errno. */ ret = fs_getfilep(fd, &filep); if (ret < 0) { goto errout; } /* Perform the fchstat operation */ ret = file_fchstat(filep, buf, flags); if (ret >= 0) { /* Successfully fchstat'ed the file */ return OK; } errout: set_errno(-ret); return ERROR; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: file_fchstat * * Description: * file_fchstat() is an internal OS interface. It is functionally similar * to the combination of fchmod/fchown/futimens standard interface except: * * - It does not modify the errno variable, * - It is not a cancellation point, * - It does not handle socket descriptors, and * - It accepts a file structure instance instead of file descriptor. * * Input Parameters: * filep - File structure instance * buf - The stat to be modified * flags - The vaild field in buf * * Returned Value: * Upon successful completion, 0 shall be returned. Otherwise, the * negative errno shall be returned to indicate the error. * ****************************************************************************/ int file_fchstat(FAR struct file *filep, FAR struct stat *buf, int flags) { FAR struct inode *inode; int ret; DEBUGASSERT(filep != NULL); /* Get the inode from the file structure */ inode = filep->f_inode; DEBUGASSERT(inode != NULL); /* Adjust and check buf and flags */ if ((flags & CH_STAT_MODE) && (buf->st_mode & ~0177777)) { return -EINVAL; } if ((flags & CH_STAT_UID) && buf->st_uid == -1) { flags &= ~CH_STAT_UID; } if ((flags & CH_STAT_GID) && buf->st_gid == -1) { flags &= ~CH_STAT_GID; } clock_gettime(CLOCK_REALTIME, &buf->st_ctim); if (flags & CH_STAT_ATIME) { if (buf->st_atim.tv_nsec == UTIME_OMIT) { flags &= ~CH_STAT_ATIME; } else if (buf->st_atim.tv_nsec == UTIME_NOW) { buf->st_atim = buf->st_ctim; } else if (buf->st_atim.tv_nsec >= 1000000000) { return -EINVAL; } } if (flags & CH_STAT_MTIME) { if (buf->st_mtim.tv_nsec == UTIME_OMIT) { flags &= ~CH_STAT_MTIME; } else if (buf->st_mtim.tv_nsec == UTIME_NOW) { buf->st_mtim = buf->st_ctim; } else if (buf->st_mtim.tv_nsec >= 1000000000) { return -EINVAL; } } /* The way we handle the chstat depends on the type of inode that we * are dealing with. */ #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(inode)) { /* The inode is a file system mountpoint. Verify that the mountpoint * supports the fchstat() method */ if (inode->u.i_mops && inode->u.i_mops->fchstat) { /* Perform the fchstat() operation */ ret = inode->u.i_mops->fchstat(filep, buf, flags); } else { ret = -ENOSYS; } } else #endif { /* The inode is part of the root pseudo file system. */ ret = inode_chstat(inode, buf, flags, 0); } return ret; } /**************************************************************************** * Name: fchmod * * Description: * The fchmod() function shall be equivalent to chmod() except that the * file whose permissions are changed is specified by the file descriptor. * * Input Parameters: * fd - Specifies the fd to be modified * mode - Specifies the permission to set * * Returned Value: * Upon successful completion, fchmod() shall return 0. * Otherwise, it shall return -1 and set errno to indicate the error. * ****************************************************************************/ int fchmod(int fd, mode_t mode) { struct stat buf; buf.st_mode = mode; return fchstat(fd, &buf, CH_STAT_MODE); } /**************************************************************************** * Name: fchown * * Description: * The fchown() function shall be equivalent to chown() except that the * file whose owner and group are changed is specified by the file * descriptor. * * Input Parameters: * fd - Specifies the fd to be modified * owner - Specifies the owner to set * group - Specifies the group to set * * Returned Value: * Upon successful completion, fchown() shall return 0. * Otherwise, it shall return -1 and set errno to indicate the error. * ****************************************************************************/ int fchown(int fd, uid_t owner, gid_t group) { struct stat buf; buf.st_uid = owner; buf.st_gid = group; return fchstat(fd, &buf, CH_STAT_UID | CH_STAT_GID); } /**************************************************************************** * Name: futimens * * Description: * futimens() update the timestamps of a file with nanosecond precision. * This contrasts with the historical utime(2) and utimes(2), which permit * only second and microsecond precision, respectively, when setting file * timestamps. * * Input Parameters: * fd - Specifies the fd to be modified * times - Specifies the time value to set * * Returned Value: * On success, futimens() return 0. * On error, -1 is returned and errno is set to indicate the error. * ****************************************************************************/ int futimens(int fd, FAR const struct timespec times[2]) { struct stat buf; if (times != NULL) { buf.st_atim = times[0]; buf.st_mtim = times[1]; } else { buf.st_atim.tv_nsec = UTIME_NOW; buf.st_mtim.tv_nsec = UTIME_NOW; } return fchstat(fd, &buf, CH_STAT_ATIME | CH_STAT_MTIME); }