@@ -21,12 +21,16 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
2121 int * nlink_out , int * uid_out , int * gid_out ,
2222 unsigned long long * size_out , struct timespec * atime_out ,
2323 struct timespec * mtime_out , struct timespec * ctime_out ,
24- int * blksize_out , unsigned long long * blocks_out )
24+ int * blksize_out , unsigned long long * blocks_out , int fd )
2525{
2626 struct stat64 buf ;
2727
28- if (lstat64 (path , & buf ) < 0 )
28+ if (fd >= 0 ) {
29+ if (fstat64 (fd , & buf ) < 0 )
30+ return (- errno );
31+ } else if (lstat64 (path , & buf ) < 0 ) {
2932 return (- errno );
33+ }
3034
3135 if (inode_out != NULL ) * inode_out = buf .st_ino ;
3236 if (mode_out != NULL ) * mode_out = buf .st_mode ;
@@ -202,58 +206,82 @@ int file_create(char *name, int ur, int uw, int ux, int gr,
202206 return (fd );
203207}
204208
205- int set_attr (const char * file , struct hostfs_iattr * attrs )
209+ int set_attr (const char * file , struct hostfs_iattr * attrs , int fd )
206210{
207- struct utimbuf buf ;
211+ struct timeval times [2 ];
212+ struct timespec atime_ts , mtime_ts ;
208213 int err , ma ;
209214
210- if (attrs -> ia_valid & HOSTFS_ATTR_MODE ){
211- if (chmod (file , attrs -> ia_mode ) != 0 ) return (- errno );
212- }
213- if (attrs -> ia_valid & HOSTFS_ATTR_UID ){
214- if (chown (file , attrs -> ia_uid , -1 )) return (- errno );
215+ if (attrs -> ia_valid & HOSTFS_ATTR_MODE ) {
216+ if (fd >= 0 ) {
217+ if (fchmod (fd , attrs -> ia_mode ) != 0 )
218+ return (- errno );
219+ } else if (chmod (file , attrs -> ia_mode ) != 0 ) {
220+ return (- errno );
221+ }
215222 }
216- if (attrs -> ia_valid & HOSTFS_ATTR_GID ){
217- if (chown (file , -1 , attrs -> ia_gid )) return (- errno );
223+ if (attrs -> ia_valid & HOSTFS_ATTR_UID ) {
224+ if (fd >= 0 ) {
225+ if (fchown (fd , attrs -> ia_uid , -1 ))
226+ return (- errno );
227+ } else if (chown (file , attrs -> ia_uid , -1 )) {
228+ return (- errno );
229+ }
218230 }
219- if (attrs -> ia_valid & HOSTFS_ATTR_SIZE ){
220- if (truncate (file , attrs -> ia_size )) return (- errno );
231+ if (attrs -> ia_valid & HOSTFS_ATTR_GID ) {
232+ if (fd >= 0 ) {
233+ if (fchown (fd , -1 , attrs -> ia_gid ))
234+ return (- errno );
235+ } else if (chown (file , -1 , attrs -> ia_gid )) {
236+ return (- errno );
237+ }
221238 }
222- ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET ;
223- if ((attrs -> ia_valid & ma ) == ma ){
224- buf .actime = attrs -> ia_atime .tv_sec ;
225- buf .modtime = attrs -> ia_mtime .tv_sec ;
226- if (utime (file , & buf ) != 0 ) return (- errno );
239+ if (attrs -> ia_valid & HOSTFS_ATTR_SIZE ) {
240+ if (fd >= 0 ) {
241+ if (ftruncate (fd , attrs -> ia_size ))
242+ return (- errno );
243+ } else if (truncate (file , attrs -> ia_size )) {
244+ return (- errno );
245+ }
227246 }
228- else {
229- struct timespec ts ;
230-
231- if (attrs -> ia_valid & HOSTFS_ATTR_ATIME_SET ){
232- err = stat_file (file , NULL , NULL , NULL , NULL , NULL ,
233- NULL , NULL , & ts , NULL , NULL , NULL );
234- if (err != 0 )
235- return (err );
236- buf .actime = attrs -> ia_atime .tv_sec ;
237- buf .modtime = ts .tv_sec ;
238- if (utime (file , & buf ) != 0 )
239- return (- errno );
247+
248+ /* Update accessed and/or modified time, in two parts: first set
249+ * times according to the changes to perform, and then call futimes()
250+ * or utimes() to apply them. */
251+ ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET );
252+ if (attrs -> ia_valid & ma ) {
253+ err = stat_file (file , NULL , NULL , NULL , NULL , NULL , NULL ,
254+ & atime_ts , & mtime_ts , NULL , NULL , NULL , fd );
255+ if (err != 0 )
256+ return err ;
257+
258+ times [0 ].tv_sec = atime_ts .tv_sec ;
259+ times [0 ].tv_usec = atime_ts .tv_nsec * 1000 ;
260+ times [1 ].tv_sec = mtime_ts .tv_sec ;
261+ times [1 ].tv_usec = mtime_ts .tv_nsec * 1000 ;
262+
263+ if (attrs -> ia_valid & HOSTFS_ATTR_ATIME_SET ) {
264+ times [0 ].tv_sec = attrs -> ia_atime .tv_sec ;
265+ times [0 ].tv_usec = attrs -> ia_atime .tv_nsec * 1000 ;
240266 }
241- if (attrs -> ia_valid & HOSTFS_ATTR_MTIME_SET ){
242- err = stat_file (file , NULL , NULL , NULL , NULL , NULL ,
243- NULL , & ts , NULL , NULL , NULL , NULL );
244- if (err != 0 )
245- return (err );
246- buf .actime = ts .tv_sec ;
247- buf .modtime = attrs -> ia_mtime .tv_sec ;
248- if (utime (file , & buf ) != 0 )
249- return (- errno );
267+ if (attrs -> ia_valid & HOSTFS_ATTR_MTIME_SET ) {
268+ times [1 ].tv_sec = attrs -> ia_mtime .tv_sec ;
269+ times [1 ].tv_usec = attrs -> ia_mtime .tv_nsec * 1000 ;
270+ }
271+
272+ if (fd >= 0 ) {
273+ if (futimes (fd , times ) != 0 )
274+ return (- errno );
275+ } else if (utimes (file , times ) != 0 ) {
276+ return (- errno );
250277 }
251278 }
279+
252280 if (attrs -> ia_valid & HOSTFS_ATTR_CTIME ) ;
253281 if (attrs -> ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME )){
254282 err = stat_file (file , NULL , NULL , NULL , NULL , NULL , NULL ,
255283 & attrs -> ia_atime , & attrs -> ia_mtime , NULL ,
256- NULL , NULL );
284+ NULL , NULL , fd );
257285 if (err != 0 ) return (err );
258286 }
259287 return (0 );
0 commit comments