| /**************************************************************************** |
| * 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 <nuttx/config.h> |
| |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <assert.h> |
| #include <errno.h> |
| |
| #include <nuttx/fs/fs.h> |
| |
| #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 valid 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); |
| } |