1// Copyright (C) 2016 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html 3/****************************************************************************** 4 * Copyright (C) 2009-2013, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 ******************************************************************************* 7 */ 8 9#include "unicode/platform.h" 10#if U_PLATFORM == U_PF_MINGW 11// *cough* - for struct stat 12#ifdef __STRICT_ANSI__ 13#undef __STRICT_ANSI__ 14#endif 15#endif 16 17#include "filetools.h" 18#include "filestrm.h" 19#include "charstr.h" 20#include "cstring.h" 21#include "unicode/putil.h" 22#include "putilimp.h" 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <sys/stat.h> 27#include <time.h> 28#include <string.h> 29 30#if U_HAVE_DIRENT_H 31#include <dirent.h> 32typedef struct dirent DIRENT; 33 34#define SKIP1 "." 35#define SKIP2 ".." 36#endif 37 38static int32_t whichFileModTimeIsLater(const char *file1, const char *file2); 39 40/* 41 * Goes through the given directory recursive to compare each file's modification time with that of the file given. 42 * Also can be given just one file to check against. Default value for isDir is FALSE. 43 */ 44U_CAPI UBool U_EXPORT2 45isFileModTimeLater(const char *filePath, const char *checkAgainst, UBool isDir) { 46 UBool isLatest = TRUE; 47 48 if (filePath == NULL || checkAgainst == NULL) { 49 return FALSE; 50 } 51 52 if (isDir == TRUE) { 53#if U_HAVE_DIRENT_H 54 DIR *pDir = NULL; 55 if ((pDir= opendir(checkAgainst)) != NULL) { 56 DIR *subDirp = NULL; 57 DIRENT *dirEntry = NULL; 58 59 while ((dirEntry = readdir(pDir)) != NULL) { 60 if (uprv_strcmp(dirEntry->d_name, SKIP1) != 0 && uprv_strcmp(dirEntry->d_name, SKIP2) != 0) { 61 UErrorCode status = U_ZERO_ERROR; 62 icu::CharString newpath(checkAgainst, -1, status); 63 newpath.append(U_FILE_SEP_STRING, -1, status); 64 newpath.append(dirEntry->d_name, -1, status); 65 if (U_FAILURE(status)) { 66 fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, u_errorName(status)); 67 return FALSE; 68 }; 69 70 if ((subDirp = opendir(newpath.data())) != NULL) { 71 /* If this new path is a directory, make a recursive call with the newpath. */ 72 closedir(subDirp); 73 isLatest = isFileModTimeLater(filePath, newpath.data(), isDir); 74 if (!isLatest) { 75 break; 76 } 77 } else { 78 int32_t latest = whichFileModTimeIsLater(filePath, newpath.data()); 79 if (latest < 0 || latest == 2) { 80 isLatest = FALSE; 81 break; 82 } 83 } 84 85 } 86 } 87 closedir(pDir); 88 } else { 89 fprintf(stderr, "Unable to open directory: %s\n", checkAgainst); 90 return FALSE; 91 } 92#endif 93 } else { 94 if (T_FileStream_file_exists(checkAgainst)) { 95 int32_t latest = whichFileModTimeIsLater(filePath, checkAgainst); 96 if (latest < 0 || latest == 2) { 97 isLatest = FALSE; 98 } 99 } else { 100 isLatest = FALSE; 101 } 102 } 103 104 return isLatest; 105} 106 107/* Compares the mod time of both files returning a number indicating which one is later. -1 if error ocurs. */ 108static int32_t whichFileModTimeIsLater(const char *file1, const char *file2) { 109 int32_t result = 0; 110 struct stat stbuf1, stbuf2; 111 112 if (stat(file1, &stbuf1) == 0 && stat(file2, &stbuf2) == 0) { 113 time_t modtime1, modtime2; 114 double diff; 115 116 modtime1 = stbuf1.st_mtime; 117 modtime2 = stbuf2.st_mtime; 118 119 diff = difftime(modtime1, modtime2); 120 if (diff < 0.0) { 121 result = 2; 122 } else if (diff > 0.0) { 123 result = 1; 124 } 125 126 } else { 127 fprintf(stderr, "Unable to get stats from file: %s or %s\n", file1, file2); 128 result = -1; 129 } 130 131 return result; 132} 133 134/* Swap the file separater character given with the new one in the file path. */ 135U_CAPI void U_EXPORT2 136swapFileSepChar(char *filePath, const char oldFileSepChar, const char newFileSepChar) { 137 for (int32_t i = 0, length = uprv_strlen(filePath); i < length; i++) { 138 filePath[i] = (filePath[i] == oldFileSepChar ) ? newFileSepChar : filePath[i]; 139 } 140} 141