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