Home | History | Annotate | Line # | Download | only in libarchive
      1 /*-
      2  * Copyright (c) 2003-2007 Tim Kientzle
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
     15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
     18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "archive_platform.h"
     27 
     28 #ifdef HAVE_SYS_STAT_H
     29 #include <sys/stat.h>
     30 #endif
     31 #ifdef HAVE_STDLIB_H
     32 #include <stdlib.h>
     33 #endif
     34 
     35 #include "archive_entry.h"
     36 #include "archive_entry_private.h"
     37 
     38 const struct stat *
     39 archive_entry_stat(struct archive_entry *entry)
     40 {
     41 	int64_t size;
     42 	struct stat *st;
     43 	if (entry->stat == NULL) {
     44 		entry->stat = calloc(1, sizeof(*st));
     45 		if (entry->stat == NULL)
     46 			return (NULL);
     47 		entry->stat_valid = 0;
     48 	}
     49 
     50 	/*
     51 	 * If none of the underlying fields have been changed, we
     52 	 * don't need to regenerate.  In theory, we could use a bitmap
     53 	 * here to flag only those items that have changed, but the
     54 	 * extra complexity probably isn't worth it.  It will be very
     55 	 * rare for anyone to change just one field then request a new
     56 	 * stat structure.
     57 	 */
     58 	if (entry->stat_valid)
     59 		return (entry->stat);
     60 
     61 	st = entry->stat;
     62 	/*
     63 	 * Use the public interfaces to extract items, so that
     64 	 * the appropriate conversions get invoked.
     65 	 */
     66 	st->st_atime = archive_entry_atime(entry);
     67 #if HAVE_STRUCT_STAT_ST_BIRTHTIME
     68 	st->st_birthtime = archive_entry_birthtime(entry);
     69 #endif
     70 	st->st_ctime = archive_entry_ctime(entry);
     71 	st->st_mtime = archive_entry_mtime(entry);
     72 	st->st_dev = archive_entry_dev(entry);
     73 	st->st_gid = (gid_t)archive_entry_gid(entry);
     74 	st->st_uid = (uid_t)archive_entry_uid(entry);
     75 	st->st_ino = (ino_t)archive_entry_ino64(entry);
     76 	st->st_nlink = archive_entry_nlink(entry);
     77 	st->st_rdev = archive_entry_rdev(entry);
     78 	size = archive_entry_size(entry);
     79 	st->st_size = (off_t)size;
     80 	if (st->st_size < 0 || (int64_t)st->st_size != size)
     81 		st->st_size = 0;
     82 	st->st_mode = archive_entry_mode(entry);
     83 
     84 	/*
     85 	 * On systems that support high-res timestamps, copy that
     86 	 * information into struct stat.
     87 	 */
     88 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
     89 	st->st_atimespec.tv_nsec = archive_entry_atime_nsec(entry);
     90 	st->st_ctimespec.tv_nsec = archive_entry_ctime_nsec(entry);
     91 	st->st_mtimespec.tv_nsec = archive_entry_mtime_nsec(entry);
     92 #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
     93 	st->st_atim.tv_nsec = archive_entry_atime_nsec(entry);
     94 	st->st_ctim.tv_nsec = archive_entry_ctime_nsec(entry);
     95 	st->st_mtim.tv_nsec = archive_entry_mtime_nsec(entry);
     96 #elif HAVE_STRUCT_STAT_ST_MTIME_N
     97 	st->st_atime_n = archive_entry_atime_nsec(entry);
     98 	st->st_ctime_n = archive_entry_ctime_nsec(entry);
     99 	st->st_mtime_n = archive_entry_mtime_nsec(entry);
    100 #elif HAVE_STRUCT_STAT_ST_UMTIME
    101 	st->st_uatime = archive_entry_atime_nsec(entry) / 1000;
    102 	st->st_uctime = archive_entry_ctime_nsec(entry) / 1000;
    103 	st->st_umtime = archive_entry_mtime_nsec(entry) / 1000;
    104 #elif HAVE_STRUCT_STAT_ST_MTIME_USEC
    105 	st->st_atime_usec = archive_entry_atime_nsec(entry) / 1000;
    106 	st->st_ctime_usec = archive_entry_ctime_nsec(entry) / 1000;
    107 	st->st_mtime_usec = archive_entry_mtime_nsec(entry) / 1000;
    108 #endif
    109 #if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
    110 	st->st_birthtimespec.tv_nsec = archive_entry_birthtime_nsec(entry);
    111 #endif
    112 
    113 	/*
    114 	 * TODO: On Linux, store 32 or 64 here depending on whether
    115 	 * the cached stat structure is a stat32 or a stat64.  This
    116 	 * will allow us to support both variants interchangeably.
    117 	 */
    118 	entry->stat_valid = 1;
    119 
    120 	return (st);
    121 }
    122