]> git.lizzy.rs Git - nothing.git/blob - src/system/file.c
Merge pull request #921 from RIscRIpt/920
[nothing.git] / src / system / file.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include "system/nth_alloc.h"
5 #ifdef __linux__
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #elif defined(_WIN32)
9 #include <Windows.h>
10 #define WINDOWS_TICK 10000000
11 #define SEC_TO_UNIX_EPOCH 11644473600LL
12 #endif
13
14 #include "system/stacktrace.h"
15 #include "file.h"
16
17 int last_modified(const char *filepath, time_t *time)
18 {
19     trace_assert(filepath);
20     trace_assert(time);
21
22 #ifdef __linux__
23
24     struct stat attr;
25     if (stat(filepath, &attr) < 0) {
26         // errno is set by stat
27         return -1;
28     }
29     *time = attr.st_mtime;
30     return 0;
31
32 #elif defined(_WIN32)
33
34     // CreateFile opens file (see flag OPEN_EXISTING)
35     HANDLE hFile = CreateFile(
36         filepath,
37         GENERIC_READ,
38         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
39         NULL,
40         OPEN_EXISTING,
41         0,
42         NULL
43     );
44     if (hFile == INVALID_HANDLE_VALUE) {
45         // TODO(#900): convert GetLastError() to errno
46         // for now let's just assume that file was not found.
47         errno = ENOENT;
48         return -1;
49     }
50     FILETIME filetime = { 0 };
51     BOOL res = GetFileTime(hFile, NULL, NULL, &filetime);
52     CloseHandle(hFile);
53     if (!res) {
54         errno = EPERM;
55         return -1;
56     }
57     unsigned long long mod_time = filetime.dwHighDateTime;
58     mod_time <<= 32;
59     mod_time |= filetime.dwLowDateTime;
60     // Taken from https://stackoverflow.com/a/6161842/1901561
61     *time = mod_time / WINDOWS_TICK - SEC_TO_UNIX_EPOCH;
62     return 0;
63
64 #elif defined(__APPLE__)
65
66     // TODO(#901): implement last_modified for Mac OS X
67     #warning last_modified is not implemented
68     return -1;
69
70 #else
71
72     #error Unsupported OS
73     return -1;
74
75 #endif
76 }
77
78 #ifdef _WIN32
79 struct DIR
80 {
81     HANDLE hFind;
82     WIN32_FIND_DATA data;
83     struct dirent *dirent;
84 };
85
86 DIR *opendir(const char *dirpath)
87 {
88     trace_assert(dirpath);
89
90     char buffer[MAX_PATH];
91     snprintf(buffer, MAX_PATH, "%s\\*", dirpath);
92
93     DIR *dir = nth_calloc(1, sizeof(DIR));
94
95     dir->hFind = FindFirstFile(buffer, &dir->data);
96     if (dir->hFind == INVALID_HANDLE_VALUE) {
97         goto fail;
98     }
99
100     return dir;
101
102 fail:
103     if (dir) {
104         free(dir);
105     }
106
107     return NULL;
108 }
109
110 struct dirent *readdir(DIR *dirp)
111 {
112     trace_assert(dirp);
113
114     if (dirp->dirent == NULL) {
115         dirp->dirent = nth_calloc(1, sizeof(struct dirent));
116     } else {
117         if(!FindNextFile(dirp->hFind, &dirp->data)) {
118             return NULL;
119         }
120     }
121
122     memset(dirp->dirent->d_name, 0, sizeof(dirp->dirent->d_name));
123
124     strncpy(
125         dirp->dirent->d_name,
126         dirp->data.cFileName,
127         sizeof(dirp->dirent->d_name) - 1);
128
129     return dirp->dirent;
130 }
131
132 void closedir(DIR *dirp)
133 {
134     trace_assert(dirp);
135
136     FindClose(dirp->hFind);
137     if (dirp->dirent) {
138         free(dirp->dirent);
139     }
140     free(dirp);
141 }
142
143 #endif