]>
Commit | Line | Data |
---|---|---|
ec250c6e | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
ec250c6e | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
ec250c6e | 6 | */ |
22a2d3d5 UG |
7 | #ifndef INCLUDE_futils_h__ |
8 | #define INCLUDE_futils_h__ | |
ec250c6e | 9 | |
5690f02e | 10 | #include "common.h" |
eae0bfdc | 11 | |
79ca2edc | 12 | #include "map.h" |
f79026b4 | 13 | #include "posix.h" |
e579e0f7 | 14 | #include "fs_path.h" |
500ec543 ET |
15 | #include "pool.h" |
16 | #include "strmap.h" | |
e579e0f7 | 17 | #include "hash.h" |
f79026b4 VM |
18 | |
19 | /** | |
20 | * Filebuffer methods | |
21 | * | |
22 | * Read whole files into an in-memory buffer for processing | |
23 | */ | |
e579e0f7 | 24 | extern int git_futils_readbuffer(git_str *obj, const char *path); |
744cc03e | 25 | extern int git_futils_readbuffer_updated( |
e579e0f7 MB |
26 | git_str *obj, |
27 | const char *path, | |
28 | unsigned char checksum[GIT_HASH_SHA1_SIZE], | |
29 | int *updated); | |
30 | extern int git_futils_readbuffer_fd(git_str *obj, git_file fd, size_t len); | |
f79026b4 | 31 | |
5312621b ET |
32 | /* Additional constants for `git_futils_writebuffer`'s `open_flags`. We |
33 | * support these internally and they will be removed before the `open` call. | |
34 | */ | |
35 | #ifndef O_FSYNC | |
36 | # define O_FSYNC (1 << 31) | |
37 | #endif | |
38 | ||
4742148d | 39 | extern int git_futils_writebuffer( |
e579e0f7 | 40 | const git_str *buf, const char *path, int open_flags, mode_t mode); |
4742148d | 41 | |
f79026b4 VM |
42 | /** |
43 | * File utils | |
44 | * | |
45 | * These are custom filesystem-related helper methods. They are | |
46 | * rather high level, and wrap the underlying POSIX methods | |
47 | * | |
0d0fa7c3 | 48 | * All these methods return 0 on success, |
f79026b4 VM |
49 | * or an error code on failure and an error message is set. |
50 | */ | |
51 | ||
f79026b4 VM |
52 | /** |
53 | * Create and open a file, while also | |
54 | * creating all the folders in its path | |
55 | */ | |
ce8cd006 | 56 | extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode); |
f79026b4 VM |
57 | |
58 | /** | |
7b3f49f0 | 59 | * Create and open a process-locked file |
f79026b4 | 60 | */ |
33127043 | 61 | extern int git_futils_creat_locked(const char *path, const mode_t mode); |
f79026b4 VM |
62 | |
63 | /** | |
7b3f49f0 | 64 | * Create and open a process-locked file, while |
f79026b4 VM |
65 | * also creating all the folders in its path |
66 | */ | |
ce8cd006 | 67 | extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode); |
f79026b4 | 68 | |
662880ca | 69 | /** |
ac2fba0e | 70 | * Create a path recursively. |
662880ca | 71 | */ |
ac2fba0e | 72 | extern int git_futils_mkdir_r(const char *path, const mode_t mode); |
662880ca | 73 | |
f79026b4 | 74 | /** |
ca1b6e54 | 75 | * Flags to pass to `git_futils_mkdir`. |
dc07184f | 76 | * |
ca1b6e54 RB |
77 | * * GIT_MKDIR_EXCL is "exclusive" - i.e. generate an error if dir exists. |
78 | * * GIT_MKDIR_PATH says to make all components in the path. | |
79 | * * GIT_MKDIR_CHMOD says to chmod the final directory entry after creation | |
80 | * * GIT_MKDIR_CHMOD_PATH says to chmod each directory component in the path | |
81 | * * GIT_MKDIR_SKIP_LAST says to leave off the last element of the path | |
3c42e4ef | 82 | * * GIT_MKDIR_SKIP_LAST2 says to leave off the last 2 elements of the path |
331e7de9 | 83 | * * GIT_MKDIR_VERIFY_DIR says confirm final item is a dir, not just EEXIST |
e74340b0 ET |
84 | * * GIT_MKDIR_REMOVE_FILES says to remove files and recreate dirs |
85 | * * GIT_MKDIR_REMOVE_SYMLINKS says to remove symlinks and recreate dirs | |
ca1b6e54 RB |
86 | * |
87 | * Note that the chmod options will be executed even if the directory already | |
88 | * exists, unless GIT_MKDIR_EXCL is given. | |
f79026b4 | 89 | */ |
ca1b6e54 RB |
90 | typedef enum { |
91 | GIT_MKDIR_EXCL = 1, | |
92 | GIT_MKDIR_PATH = 2, | |
93 | GIT_MKDIR_CHMOD = 4, | |
94 | GIT_MKDIR_CHMOD_PATH = 8, | |
331e7de9 | 95 | GIT_MKDIR_SKIP_LAST = 16, |
3c42e4ef RB |
96 | GIT_MKDIR_SKIP_LAST2 = 32, |
97 | GIT_MKDIR_VERIFY_DIR = 64, | |
e74340b0 | 98 | GIT_MKDIR_REMOVE_FILES = 128, |
e579e0f7 | 99 | GIT_MKDIR_REMOVE_SYMLINKS = 256 |
ca1b6e54 RB |
100 | } git_futils_mkdir_flags; |
101 | ||
1d50b364 ET |
102 | struct git_futils_mkdir_perfdata |
103 | { | |
104 | size_t stat_calls; | |
105 | size_t mkdir_calls; | |
106 | size_t chmod_calls; | |
107 | }; | |
108 | ||
500ec543 ET |
109 | struct git_futils_mkdir_options |
110 | { | |
111 | git_strmap *dir_map; | |
112 | git_pool *pool; | |
113 | struct git_futils_mkdir_perfdata perfdata; | |
114 | }; | |
115 | ||
ca1b6e54 RB |
116 | /** |
117 | * Create a directory or entire path. | |
118 | * | |
119 | * This makes a directory (and the entire path leading up to it if requested), | |
120 | * and optionally chmods the directory immediately after (or each part of the | |
121 | * path if requested). | |
122 | * | |
ac2fba0e | 123 | * @param path The path to create, relative to base. |
ca1b6e54 RB |
124 | * @param base Root for relative path. These directories will never be made. |
125 | * @param mode The mode to use for created directories. | |
126 | * @param flags Combination of the mkdir flags above. | |
ac2fba0e | 127 | * @param opts Extended options, or null. |
ca1b6e54 RB |
128 | * @return 0 on success, else error code |
129 | */ | |
ac2fba0e | 130 | extern int git_futils_mkdir_relative(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts); |
1d50b364 ET |
131 | |
132 | /** | |
ac2fba0e | 133 | * Create a directory or entire path. Similar to `git_futils_mkdir_relative` |
1d50b364 ET |
134 | * without performance data. |
135 | */ | |
ac2fba0e | 136 | extern int git_futils_mkdir(const char *path, mode_t mode, uint32_t flags); |
f79026b4 VM |
137 | |
138 | /** | |
139 | * Create all the folders required to contain | |
140 | * the full path of a file | |
141 | */ | |
ce8cd006 | 142 | extern int git_futils_mkpath2file(const char *path, const mode_t mode); |
f79026b4 | 143 | |
331e7de9 RB |
144 | /** |
145 | * Flags to pass to `git_futils_rmdir_r`. | |
146 | * | |
147 | * * GIT_RMDIR_EMPTY_HIERARCHY - the default; remove hierarchy of empty | |
148 | * dirs and generate error if any files are found. | |
149 | * * GIT_RMDIR_REMOVE_FILES - attempt to remove files in the hierarchy. | |
150 | * * GIT_RMDIR_SKIP_NONEMPTY - skip non-empty directories with no error. | |
151 | * * GIT_RMDIR_EMPTY_PARENTS - remove containing directories up to base | |
152 | * if removing this item leaves them empty | |
ad9a921b | 153 | * * GIT_RMDIR_REMOVE_BLOCKERS - remove blocking file that causes ENOTDIR |
219d3457 | 154 | * * GIT_RMDIR_SKIP_ROOT - don't remove root directory itself |
331e7de9 | 155 | */ |
555aa453 | 156 | typedef enum { |
331e7de9 RB |
157 | GIT_RMDIR_EMPTY_HIERARCHY = 0, |
158 | GIT_RMDIR_REMOVE_FILES = (1 << 0), | |
159 | GIT_RMDIR_SKIP_NONEMPTY = (1 << 1), | |
160 | GIT_RMDIR_EMPTY_PARENTS = (1 << 2), | |
ad9a921b | 161 | GIT_RMDIR_REMOVE_BLOCKERS = (1 << 3), |
e579e0f7 | 162 | GIT_RMDIR_SKIP_ROOT = (1 << 4) |
331e7de9 | 163 | } git_futils_rmdir_flags; |
555aa453 | 164 | |
df743c7d | 165 | /** |
1744fafe | 166 | * Remove path and any files and directories beneath it. |
555aa453 | 167 | * |
926acbcf | 168 | * @param path Path to the top level directory to process. |
0d64bef9 | 169 | * @param base Root for relative path. |
331e7de9 | 170 | * @param flags Combination of git_futils_rmdir_flags values |
555aa453 | 171 | * @return 0 on success; -1 on error. |
df743c7d | 172 | */ |
331e7de9 | 173 | extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags); |
df743c7d | 174 | |
f79026b4 | 175 | /** |
e579e0f7 MB |
176 | * Create and open a temporary file with a `_git2_` suffix in a |
177 | * protected directory; the file created will created will honor | |
178 | * the current `umask`. Writes the filename into path_out. | |
179 | * | |
180 | * This function uses a high-quality PRNG seeded by the system's | |
181 | * entropy pool _where available_ and falls back to a simple seed | |
182 | * (time plus system information) when not. This is suitable for | |
183 | * writing within a protected directory, but the system's safe | |
184 | * temporary file creation functions should be preferred where | |
185 | * available when writing into world-writable (temp) directories. | |
186 | * | |
97769280 | 187 | * @return On success, an open file descriptor, else an error code < 0. |
f79026b4 | 188 | */ |
e579e0f7 | 189 | extern int git_futils_mktmp(git_str *path_out, const char *filename, mode_t mode); |
f79026b4 | 190 | |
f79026b4 VM |
191 | /** |
192 | * Move a file on the filesystem, create the | |
193 | * destination path if it doesn't exist | |
194 | */ | |
ce8cd006 | 195 | extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode); |
f79026b4 | 196 | |
ca1b6e54 | 197 | /** |
85bd1746 | 198 | * Copy a file |
ca1b6e54 | 199 | * |
85bd1746 | 200 | * The filemode will be used for the newly created file. |
ca1b6e54 | 201 | */ |
85bd1746 | 202 | extern int git_futils_cp( |
ca1b6e54 RB |
203 | const char *from, |
204 | const char *to, | |
85bd1746 | 205 | mode_t filemode); |
ca1b6e54 | 206 | |
8f09a98e | 207 | /** |
27051d4e ET |
208 | * Set the files atime and mtime to the given time, or the current time |
209 | * if `ts` is NULL. | |
8f09a98e | 210 | */ |
27051d4e | 211 | extern int git_futils_touch(const char *path, time_t *when); |
8f09a98e | 212 | |
ca1b6e54 RB |
213 | /** |
214 | * Flags that can be passed to `git_futils_cp_r`. | |
18f08264 RB |
215 | * |
216 | * - GIT_CPDIR_CREATE_EMPTY_DIRS: create directories even if there are no | |
217 | * files under them (otherwise directories will only be created lazily | |
218 | * when a file inside them is copied). | |
219 | * - GIT_CPDIR_COPY_SYMLINKS: copy symlinks, otherwise they are ignored. | |
220 | * - GIT_CPDIR_COPY_DOTFILES: copy files with leading '.', otherwise ignored. | |
221 | * - GIT_CPDIR_OVERWRITE: overwrite pre-existing files with source content, | |
222 | * otherwise they are silently skipped. | |
223 | * - GIT_CPDIR_CHMOD_DIRS: explicitly chmod directories to `dirmode` | |
224 | * - GIT_CPDIR_SIMPLE_TO_MODE: default tries to replicate the mode of the | |
225 | * source file to the target; with this flag, always use 0666 (or 0777 if | |
226 | * source has exec bits set) for target. | |
94f742ba | 227 | * - GIT_CPDIR_LINK_FILES will try to use hardlinks for the files |
ca1b6e54 RB |
228 | */ |
229 | typedef enum { | |
3c42e4ef RB |
230 | GIT_CPDIR_CREATE_EMPTY_DIRS = (1u << 0), |
231 | GIT_CPDIR_COPY_SYMLINKS = (1u << 1), | |
232 | GIT_CPDIR_COPY_DOTFILES = (1u << 2), | |
233 | GIT_CPDIR_OVERWRITE = (1u << 3), | |
18f08264 RB |
234 | GIT_CPDIR_CHMOD_DIRS = (1u << 4), |
235 | GIT_CPDIR_SIMPLE_TO_MODE = (1u << 5), | |
e579e0f7 | 236 | GIT_CPDIR_LINK_FILES = (1u << 6) |
ca1b6e54 RB |
237 | } git_futils_cpdir_flags; |
238 | ||
239 | /** | |
240 | * Copy a directory tree. | |
241 | * | |
242 | * This copies directories and files from one root to another. You can | |
e579e0f7 | 243 | * pass a combination of GIT_CPDIR flags as defined above. |
ca1b6e54 RB |
244 | * |
245 | * If you pass the CHMOD flag, then the dirmode will be applied to all | |
e579e0f7 | 246 | * directories that are created during the copy, overriding the natural |
ca1b6e54 RB |
247 | * permissions. If you do not pass the CHMOD flag, then the dirmode |
248 | * will actually be copied from the source files and the `dirmode` arg | |
249 | * will be ignored. | |
250 | */ | |
251 | extern int git_futils_cp_r( | |
252 | const char *from, | |
253 | const char *to, | |
254 | uint32_t flags, | |
255 | mode_t dirmode); | |
256 | ||
ae9e29fd | 257 | /** |
deafee7b | 258 | * Open a file readonly and set error if needed. |
ae9e29fd | 259 | */ |
deafee7b | 260 | extern int git_futils_open_ro(const char *path); |
ae9e29fd | 261 | |
eae0bfdc PP |
262 | /** |
263 | * Truncate a file, creating it if it doesn't exist. | |
264 | */ | |
265 | extern int git_futils_truncate(const char *path, int mode); | |
266 | ||
f79026b4 VM |
267 | /** |
268 | * Get the filesize in bytes of a file | |
269 | */ | |
22a2d3d5 | 270 | extern int git_futils_filesize(uint64_t *out, git_file fd); |
502acd16 | 271 | |
c25aa7cd | 272 | #define GIT_PERMS_IS_EXEC(MODE) (((MODE) & 0100) != 0) |
a7fcc44d RB |
273 | #define GIT_PERMS_CANONICAL(MODE) (GIT_PERMS_IS_EXEC(MODE) ? 0755 : 0644) |
274 | #define GIT_PERMS_FOR_WRITE(MODE) (GIT_PERMS_IS_EXEC(MODE) ? 0777 : 0666) | |
f240acce | 275 | |
74fa4bfa | 276 | #define GIT_MODE_PERMS_MASK 0777 |
af22dabb RB |
277 | #define GIT_MODE_TYPE_MASK 0170000 |
278 | #define GIT_MODE_TYPE(MODE) ((MODE) & GIT_MODE_TYPE_MASK) | |
9be5be47 | 279 | #define GIT_MODE_ISBLOB(MODE) (GIT_MODE_TYPE(MODE) == GIT_MODE_TYPE(GIT_FILEMODE_BLOB)) |
74fa4bfa | 280 | |
b6c93aef RB |
281 | /** |
282 | * Convert a mode_t from the OS to a legal git mode_t value. | |
283 | */ | |
284 | extern mode_t git_futils_canonical_mode(mode_t raw_mode); | |
285 | ||
286 | ||
20e7f426 SP |
287 | /** |
288 | * Read-only map all or part of a file into memory. | |
289 | * When possible this function should favor a virtual memory | |
290 | * style mapping over some form of malloc()+read(), as the | |
291 | * data access will be random and is not likely to touch the | |
292 | * majority of the region requested. | |
293 | * | |
294 | * @param out buffer to populate with the mapping information. | |
295 | * @param fd open descriptor to configure the mapping from. | |
296 | * @param begin first byte to map, this should be page aligned. | |
c05a55b0 | 297 | * @param len number of bytes to map. |
20e7f426 | 298 | * @return |
0d0fa7c3 RB |
299 | * - 0 on success; |
300 | * - -1 on error. | |
20e7f426 | 301 | */ |
f79026b4 | 302 | extern int git_futils_mmap_ro( |
79ca2edc | 303 | git_map *out, |
20e7f426 | 304 | git_file fd, |
22a2d3d5 | 305 | off64_t begin, |
20e7f426 SP |
306 | size_t len); |
307 | ||
74fa4bfa RB |
308 | /** |
309 | * Read-only map an entire file. | |
310 | * | |
311 | * @param out buffer to populate with the mapping information. | |
312 | * @param path path to file to be opened. | |
313 | * @return | |
0d0fa7c3 RB |
314 | * - 0 on success; |
315 | * - GIT_ENOTFOUND if not found; | |
316 | * - -1 on an unspecified OS related error. | |
74fa4bfa RB |
317 | */ |
318 | extern int git_futils_mmap_ro_file( | |
319 | git_map *out, | |
320 | const char *path); | |
321 | ||
20e7f426 SP |
322 | /** |
323 | * Release the memory associated with a previous memory mapping. | |
324 | * @param map the mapping description previously configured. | |
325 | */ | |
f79026b4 | 326 | extern void git_futils_mmap_free(git_map *map); |
20e7f426 | 327 | |
8651c10f BS |
328 | /** |
329 | * Create a "fake" symlink (text file containing the target path). | |
330 | * | |
22a2d3d5 UG |
331 | * @param target original symlink target |
332 | * @param path symlink file to be created | |
8651c10f BS |
333 | * @return 0 on success, -1 on error |
334 | */ | |
22a2d3d5 | 335 | extern int git_futils_fake_symlink(const char *target, const char *path); |
8651c10f | 336 | |
c8b511f3 RB |
337 | /** |
338 | * A file stamp represents a snapshot of information about a file that can | |
339 | * be used to test if the file changes. This portable implementation is | |
340 | * based on stat data about that file, but it is possible that OS specific | |
341 | * versions could be implemented in the future. | |
342 | */ | |
744cc03e | 343 | typedef struct { |
0226f7dd | 344 | struct timespec mtime; |
22a2d3d5 | 345 | uint64_t size; |
744cc03e | 346 | unsigned int ino; |
c1f61af6 | 347 | } git_futils_filestamp; |
744cc03e RB |
348 | |
349 | /** | |
350 | * Compare stat information for file with reference info. | |
351 | * | |
c8b511f3 | 352 | * This function updates the file stamp to current data for the given path |
7d490872 RB |
353 | * and returns 0 if the file is up-to-date relative to the prior setting, |
354 | * 1 if the file has been changed, or GIT_ENOTFOUND if the file doesn't | |
ac3d33df | 355 | * exist. This will not call git_error_set, so you must set the error if you |
7d490872 | 356 | * plan to return an error. |
744cc03e | 357 | * |
c8b511f3 RB |
358 | * @param stamp File stamp to be checked |
359 | * @param path Path to stat and check if changed | |
7d490872 | 360 | * @return 0 if up-to-date, 1 if out-of-date, GIT_ENOTFOUND if cannot stat |
744cc03e | 361 | */ |
c1f61af6 VM |
362 | extern int git_futils_filestamp_check( |
363 | git_futils_filestamp *stamp, const char *path); | |
c8b511f3 RB |
364 | |
365 | /** | |
366 | * Set or reset file stamp data | |
367 | * | |
368 | * This writes the target file stamp. If the source is NULL, this will set | |
369 | * the target stamp to values that will definitely be out of date. If the | |
370 | * source is not NULL, this copies the source values to the target. | |
371 | * | |
372 | * @param tgt File stamp to write to | |
373 | * @param src File stamp to copy from or NULL to clear the target | |
374 | */ | |
c1f61af6 VM |
375 | extern void git_futils_filestamp_set( |
376 | git_futils_filestamp *tgt, const git_futils_filestamp *src); | |
744cc03e | 377 | |
823c0e9c RB |
378 | /** |
379 | * Set file stamp data from stat structure | |
380 | */ | |
381 | extern void git_futils_filestamp_set_from_stat( | |
382 | git_futils_filestamp *stamp, struct stat *st); | |
383 | ||
1229e1c4 ET |
384 | /** |
385 | * `fsync` the parent directory of the given path, if `fsync` is | |
386 | * supported for directories on this platform. | |
387 | * | |
388 | * @param path Path of the directory to sync. | |
389 | * @return 0 on success, -1 on error | |
390 | */ | |
391 | extern int git_futils_fsync_dir(const char *path); | |
392 | ||
393 | /** | |
394 | * `fsync` the parent directory of the given path, if `fsync` is | |
395 | * supported for directories on this platform. | |
396 | * | |
397 | * @param path Path of the file whose parent directory should be synced. | |
398 | * @return 0 on success, -1 on error | |
399 | */ | |
400 | extern int git_futils_fsync_parent(const char *path); | |
401 | ||
eae0bfdc | 402 | #endif |