-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwin64_files.h
205 lines (165 loc) · 7.73 KB
/
win64_files.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#pragma once
/*
In this file:
functions to simplify working with windows' file system.
- get_only_files_in_dir(...) to know which files only are in a directory
- get_only_folders_in_dir(...) to know which folders only are in a directory
- get_drive_names(...) to know which drives you have in your pc
- win64_get_last_write_time(...) to know when a file was last edited
- win64_write_file(...) to write data to a file
- win64_read_entire_file(...) to read the entire contents of a file
*/
#ifndef GYOFIRST
#include "first.h"
#endif
// API(cogno): since array allocates, we can make a get_next_file_in_dir to avoid the allocation. It's basically like str_split_left which returns the single split instead of str_split that returns the array that must be allocated.
bool win64_get_only_files_in_dir(str folder_path, Array<str>* filenames) {
StrBuilder builder = make_str_builder();
defer { free(builder.ptr); };
str_builder_append(&builder, folder_path);
str_builder_append(&builder, "\\*");
str_builder_append_raw(&builder, (u8)0);
WIN32_FIND_DATA win_file_data = {};
HANDLE handle = FindFirstFile((char*)builder.ptr, &win_file_data);
defer { FindClose(handle); };
if(handle == INVALID_HANDLE_VALUE) return false;
str_builder_remove_last_bytes(&builder, 2);
StrBuilder copy = str_builder_copy(&builder);
defer { free(copy.ptr); };
do {
// reset str builder into the initial folder path
copy.size = builder.size;
str_builder_append(©, win_file_data.cFileName);
// .sys files are used by the os, we have to skip them
str to_check = str_builder_get_str(©);
bool is_sys_file = str_ends_with(to_check, ".sys");
if(is_sys_file) continue;
// get info if it's a file or not
str_builder_append_raw(©, (u8)0);
auto result = GetFileAttributes((const char*)copy.ptr);
if((int)result < 0) {
DWORD err = GetLastError();
if(err == ERROR_SHARING_VIOLATION) continue; // skip files we can't access
return false;
}
if(result & FILE_ATTRIBUTE_ARCHIVE) {
str file_name = str_copy((const char*)win_file_data.cFileName); // else it doesn't live outside this function
array_append(filenames, file_name);
}
} while(FindNextFile(handle, &win_file_data));
auto err = GetLastError();
if(err != ERROR_NO_MORE_FILES) return false;
return true;
}
bool win64_get_only_folders_in_dir(str folder_path, Array<str>* folders) {
StrBuilder builder = make_str_builder();
defer { free(builder.ptr); };
str_builder_append(&builder, folder_path);
str_builder_append(&builder, "\\*");
str_builder_append_raw(&builder, (u8)0);
WIN32_FIND_DATA win_file_data = {};
HANDLE handle = FindFirstFile((char*)builder.ptr, &win_file_data);
defer { FindClose(handle); };
if(handle == INVALID_HANDLE_VALUE) return false;
str_builder_remove_last_bytes(&builder, 2);
StrBuilder copy = str_builder_copy(&builder);
defer { free(copy.ptr); };
do {
// reset str builder into the initial folder path
copy.size = builder.size;
str_builder_append(©, win_file_data.cFileName);
// .sys files are used by the os, we have to skip them
str to_check = str_builder_get_str(©);
bool is_sys_file = str_ends_with(to_check, ".sys");
if(is_sys_file) continue;
// get info if it's a file or not
str_builder_append_raw(©, (u8)0);
auto result = GetFileAttributes((const char*)copy.ptr);
if((int)result < 0) {
DWORD err = GetLastError();
if(err == ERROR_SHARING_VIOLATION) continue; // skip files we can't access
return false;
}
if(result & FILE_ATTRIBUTE_DIRECTORY) {
// NOTE(cogno): windows is so fucking stupid it adds '.' and '..' as folders, we need to filter them out
str folder_name = str_copy(win_file_data.cFileName); // else it doesn't live outside this function
if(str_matches(folder_name, ".")) continue;
if(str_matches(folder_name, "..")) continue;
array_append(folders, folder_name);
}
} while(FindNextFile(handle, &win_file_data));
auto err = GetLastError();
if(err != ERROR_NO_MORE_FILES) return false;
return true;
}
// NOTE(cogno): each name will be terminated with ':', so you'll see "C:" etc.
bool win64_get_drive_names(Array<str>* drive_names) {
const int BUFF_SIZE = 255;
char buf[BUFF_SIZE];
// get the drive letters as a set of strings
int sz = GetLogicalDriveStrings(sizeof(buf), buf);
if(sz == 0) return false;
if(!ASSERT(sz <= BUFF_SIZE, "buffer not big enough (needs at least % bytes)", sz)) return false;
// buf now contains a list of all the drive letters. Each drive letter is
// terminated with '\0' and the last one is terminated by two consecutive '\0' bytes.
char* start = buf;
while(true) {
char ch = *start;
if(ch == 0) break;
str drive_name = str_copy(start);
drive_name.size--; //remove the '\'
array_append(drive_names, drive_name);
start += drive_name.size + 2;
}
return drive_names->size > 0;
}
inline FILETIME win64_get_last_write_time(char *filename) {
FILETIME last_write_time = {};
if(!ASSERT(filename != NULL, "no input file given")) return last_write_time;
WIN32_FIND_DATA find_data;
HANDLE find_handle = FindFirstFileA(filename, &find_data);
if (find_handle != INVALID_HANDLE_VALUE) {
last_write_time = find_data.ftLastWriteTime;
FindClose(find_handle);
}
return last_write_time;
}
// Writes input data to a file which is created automatically if the file doesn't exist.
// Returns true if the file is created and the data is saved without any problem, false otherwise.
// For extended error information you should look at win64_print_error().
bool win64_write_file(const char* filename, u8* file_data, u32 data_size) {
auto file_handle = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (file_handle == INVALID_HANDLE_VALUE) return false;
defer {
bool ok = CloseHandle(file_handle);
ASSERT(ok, "couldn't close file");
};
DWORD bytes_written;
WriteFile(file_handle, file_data, data_size, &bytes_written, 0);
return true;
}
// Reads the entire file into a buffer allocated automatically.
// Optionally writes into bytes_read how big the file is (if NULL it's ignored).
// Returns NULL if file cannot be read for some reason.
// For extended error information you should look at win64_print_error().
u8* win64_read_entire_file(const char* filename, Allocator alloc, u32* bytes_read) {
if(!ASSERT(filename != NULL, "No input file given.")) return NULL;
if(!ASSERT(alloc.handle != NULL, "No allocator given!")) return NULL;
auto file_handle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (file_handle == INVALID_HANDLE_VALUE) return NULL;
defer {
bool ok = CloseHandle(file_handle);
ASSERT(ok, "couldn't close file");
};
DWORD file_size = GetFileSize(file_handle, NULL);
if (file_size == INVALID_FILE_SIZE) return NULL;
auto* allocated = mem_alloc(alloc, file_size);
if(allocated == NULL) return NULL;
DWORD bytes_read_win64;
ReadFile(file_handle, allocated, file_size, &bytes_read_win64, 0);
if (bytes_read != NULL) *bytes_read = (u32)bytes_read_win64;
return (u8*)allocated;
}
u8* win64_read_entire_file(const char* filename, u32* bytes_read) {
return win64_read_entire_file(filename, default_allocator, bytes_read);
}