Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  *  @file
0005  *
0006  *  @ingroup libcsupport
0007  *
0008  *  @brief Set file access and modification times in nanoseconds.
0009  */
0010 
0011 /*
0012  * COPYRIGHT (C) 2021 On-Line Applications Research Corporation (OAR).
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <rtems/libio_.h>
0041 #include <rtems/score/todimpl.h>
0042 
0043 #include <fcntl.h>
0044 #include <string.h>
0045 
0046 /*
0047  * Make sure that tv_nsec is either UTIME_NOW, UTIME_OMIT, a value
0048  * greater than zero, or a value less-than a billion.
0049  *
0050  * These guidelines come from the description of the EINVAL errors on
0051  * https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
0052  */
0053 bool rtems_filesystem_utime_tv_nsec_valid(struct timespec time)
0054 {
0055   if ( time.tv_nsec == UTIME_NOW ) {
0056     return true;
0057   }
0058 
0059   if ( time.tv_nsec == UTIME_OMIT ) {
0060     return true;
0061   }
0062 
0063   if ( time.tv_nsec < 0 ) {
0064     return false;
0065   }
0066 
0067   if ( time.tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) {
0068     return false;
0069   }
0070 
0071   return true;
0072 }
0073 
0074 /* Determine whether the access and modified timestamps can be updated */
0075 int rtems_filesystem_utime_check_permissions(
0076   const rtems_filesystem_location_info_t * currentloc,
0077   const struct timespec times[2]
0078 )
0079 {
0080   struct stat st = {};
0081   int rv;
0082   bool write_access;
0083 
0084   rv = (*currentloc->handlers->fstat_h)( currentloc, &st );
0085   if ( rv != 0 ) {
0086     rtems_set_errno_and_return_minus_one( ENOENT );
0087   }
0088 
0089   write_access = rtems_filesystem_check_access(
0090     RTEMS_FS_PERMS_WRITE,
0091     st.st_mode,
0092     st.st_uid,
0093     st.st_gid
0094   );
0095 
0096   /*
0097    * The logic for the EACCES error is an inverted subset of the EPERM
0098    * conditional according to the POSIX standard.
0099    */
0100   if ( (times == NULL) ||
0101      ( (times[0].tv_nsec == UTIME_NOW) && (times[1].tv_nsec == UTIME_NOW) )) {
0102       if ( !write_access ) {
0103         rtems_set_errno_and_return_minus_one( EACCES );
0104       }
0105   } else {
0106     if ( times[0].tv_nsec != UTIME_OMIT || times[1].tv_nsec != UTIME_OMIT ) {
0107       if ( !write_access ) {
0108         rtems_set_errno_and_return_minus_one( EPERM );
0109       }
0110     }
0111   }
0112 
0113   return 0;
0114 }
0115 
0116 /*
0117  * Determine if the current time needs to be gotten, and then check
0118  * whether the values in times are valid.
0119  */
0120 int rtems_filesystem_utime_update(
0121   const struct timespec times[2],
0122   struct timespec new_times[2]
0123 )
0124 {
0125   bool got_time = false;
0126   struct timespec now;
0127 
0128   /*
0129    * If times is NULL, it's equivalent to adding UTIME_NOW in both time
0130    * elements
0131    */
0132   if ( times == NULL ) {
0133     _Timespec_Set( &new_times[0], 0, UTIME_NOW );
0134     _Timespec_Set( &new_times[1], 0, UTIME_NOW );
0135   } else {
0136     new_times[0] = times[0];
0137     new_times[1] = times[1];
0138   }
0139 
0140   if ( new_times[0].tv_nsec == UTIME_NOW ) {
0141     clock_gettime( CLOCK_REALTIME, &now );
0142     new_times[0] = now;
0143     got_time = true;
0144   }
0145 
0146   if ( new_times[1].tv_nsec == UTIME_NOW ) {
0147     if ( !got_time ) {
0148       clock_gettime( CLOCK_REALTIME, &now );
0149     }
0150     new_times[1] = now;
0151   }
0152 
0153   if ( !_Timespec_Is_non_negative( &new_times[0] ) ) {
0154     rtems_set_errno_and_return_minus_one( EINVAL );
0155   }
0156 
0157   if ( !_Timespec_Is_non_negative( &new_times[1] ) ) {
0158     rtems_set_errno_and_return_minus_one( EINVAL );
0159   }
0160 
0161   if ( !rtems_filesystem_utime_tv_nsec_valid( new_times[0] ) ) {
0162     rtems_set_errno_and_return_minus_one( EINVAL );
0163   }
0164 
0165   if ( !rtems_filesystem_utime_tv_nsec_valid( new_times[1] ) ) {
0166     rtems_set_errno_and_return_minus_one( EINVAL );
0167   }
0168 
0169   return 0;
0170 }
0171 
0172 /**
0173  *  https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/futimens.html
0174  *
0175  *  Set file access and modification times
0176  */
0177 int utimensat(
0178   int                    fd,
0179   const char            *path,
0180   const struct timespec  times[2],
0181   int                    flag
0182 )
0183 {
0184   int rv = 0;
0185   rtems_filesystem_eval_path_context_t ctx;
0186   int eval_flags = RTEMS_FS_FOLLOW_LINK;
0187   const rtems_filesystem_location_info_t *currentloc = NULL;
0188   struct timespec new_times[2];
0189 
0190   /*
0191    * RTEMS does not currently support operating on a real file descriptor
0192    */
0193   if ( fd != AT_FDCWD ) {
0194     rtems_set_errno_and_return_minus_one( ENOSYS );
0195   }
0196 
0197   /*
0198    * RTEMS does not currently support AT_SYMLINK_NOFOLLOW
0199    */
0200   if ( flag != 0 ) {
0201     rtems_set_errno_and_return_minus_one( ENOSYS );
0202   }
0203 
0204   rv = rtems_filesystem_utime_update( times, new_times );
0205   if ( rv != 0 ) {
0206     return rv;
0207   }
0208 
0209   currentloc = rtems_filesystem_eval_path_start( &ctx, path, eval_flags );
0210 
0211   rv = rtems_filesystem_utime_check_permissions( currentloc, times );
0212   if ( rv != 0 ) {
0213     rtems_filesystem_eval_path_cleanup( &ctx );
0214     return rv;
0215   }
0216 
0217   rv = (*currentloc->mt_entry->ops->utimens_h)(
0218     currentloc,
0219     new_times
0220   );
0221 
0222   rtems_filesystem_eval_path_cleanup( &ctx );
0223 
0224   return rv;
0225 }