1  /*
       2   * uuid_time.c --- Interpret the time field from a uuid.  This program
       3   * 	violates the UUID abstraction barrier by reaching into the guts
       4   *	of a UUID and interpreting it.
       5   *
       6   * Copyright (C) 1998, 1999 Theodore Ts'o.
       7   *
       8   * %Begin-Header%
       9   * Redistribution and use in source and binary forms, with or without
      10   * modification, are permitted provided that the following conditions
      11   * are met:
      12   * 1. Redistributions of source code must retain the above copyright
      13   *    notice, and the entire permission notice in its entirety,
      14   *    including the disclaimer of warranties.
      15   * 2. Redistributions in binary form must reproduce the above copyright
      16   *    notice, this list of conditions and the following disclaimer in the
      17   *    documentation and/or other materials provided with the distribution.
      18   * 3. The name of the author may not be used to endorse or promote
      19   *    products derived from this software without specific prior
      20   *    written permission.
      21   *
      22   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
      23   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      24   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
      25   * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
      26   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      27   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
      28   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
      29   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      30   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      31   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
      32   * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
      33   * DAMAGE.
      34   * %End-Header%
      35   */
      36  
      37  #ifdef _WIN32
      38  #define _WIN32_WINNT 0x0500
      39  #include <windows.h>
      40  #define UUID MYUUID
      41  #endif
      42  
      43  #include <stdio.h>
      44  #ifdef HAVE_UNISTD_H
      45  #include <unistd.h>
      46  #endif
      47  #include <stdlib.h>
      48  #include <sys/types.h>
      49  #ifdef HAVE_SYS_TIME_H
      50  #include <sys/time.h>
      51  #endif
      52  #include <time.h>
      53  
      54  #include "uuidP.h"
      55  
      56  time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
      57  {
      58  	struct timeval		tv;
      59  	struct uuid		uuid;
      60  	uint32_t		high;
      61  	uint64_t		clock_reg;
      62  
      63  	uuid_unpack(uu, &uuid);
      64  
      65  	high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
      66  	clock_reg = uuid.time_low | ((uint64_t) high << 32);
      67  
      68  	clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
      69  	tv.tv_sec = clock_reg / 10000000;
      70  	tv.tv_usec = (clock_reg % 10000000) / 10;
      71  
      72  	if (ret_tv)
      73  		*ret_tv = tv;
      74  
      75  	return tv.tv_sec;
      76  }
      77  
      78  int uuid_type(const uuid_t uu)
      79  {
      80  	struct uuid		uuid;
      81  
      82  	uuid_unpack(uu, &uuid);
      83  	return ((uuid.time_hi_and_version >> 12) & 0xF);
      84  }
      85  
      86  int uuid_variant(const uuid_t uu)
      87  {
      88  	struct uuid		uuid;
      89  	int			var;
      90  
      91  	uuid_unpack(uu, &uuid);
      92  	var = uuid.clock_seq;
      93  
      94  	if ((var & 0x8000) == 0)
      95  		return UUID_VARIANT_NCS;
      96  	if ((var & 0x4000) == 0)
      97  		return UUID_VARIANT_DCE;
      98  	if ((var & 0x2000) == 0)
      99  		return UUID_VARIANT_MICROSOFT;
     100  	return UUID_VARIANT_OTHER;
     101  }
     102  
     103  #ifdef DEBUG
     104  static const char *variant_string(int variant)
     105  {
     106  	switch (variant) {
     107  	case UUID_VARIANT_NCS:
     108  		return "NCS";
     109  	case UUID_VARIANT_DCE:
     110  		return "DCE";
     111  	case UUID_VARIANT_MICROSOFT:
     112  		return "Microsoft";
     113  	default:
     114  		return "Other";
     115  	}
     116  }
     117  
     118  
     119  int
     120  main(int argc, char **argv)
     121  {
     122  	uuid_t		buf;
     123  	time_t		time_reg;
     124  	struct timeval	tv;
     125  	int		type, variant;
     126  
     127  	if (argc != 2) {
     128  		fprintf(stderr, "Usage: %s uuid\n", argv[0]);
     129  		exit(1);
     130  	}
     131  	if (uuid_parse(argv[1], buf)) {
     132  		fprintf(stderr, "Invalid UUID: %s\n", argv[1]);
     133  		exit(1);
     134  	}
     135  	variant = uuid_variant(buf);
     136  	type = uuid_type(buf);
     137  	time_reg = uuid_time(buf, &tv);
     138  
     139  	printf("UUID variant is %d (%s)\n", variant, variant_string(variant));
     140  	if (variant != UUID_VARIANT_DCE) {
     141  		printf("Warning: This program only knows how to interpret "
     142  		       "DCE UUIDs.\n\tThe rest of the output is likely "
     143  		       "to be incorrect!!\n");
     144  	}
     145  	printf("UUID type is %d", type);
     146  	switch (type) {
     147  	case 1:
     148  		printf(" (time based)\n");
     149  		break;
     150  	case 2:
     151  		printf(" (DCE)\n");
     152  		break;
     153  	case 3:
     154  		printf(" (name-based)\n");
     155  		break;
     156  	case 4:
     157  		printf(" (random)\n");
     158  		break;
     159  	default:
     160  		printf("\n");
     161  	}
     162  	if (type != 1) {
     163  		printf("Warning: not a time-based UUID, so UUID time "
     164  		       "decoding will likely not work!\n");
     165  	}
     166  	printf("UUID time is: (%"PRId64", %"PRId64"): %s\n",
     167  		(int64_t)tv.tv_sec, (int64_t)tv.tv_usec, ctime(&time_reg));
     168  
     169  	return 0;
     170  }
     171  #endif