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