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