1 /* 2 * Copyright (C) the libgit2 contributors. All rights reserved. 3 * 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. 6 */ 7 #ifndef INCLUDE_futils_h__ 8 #define INCLUDE_futils_h__ 9 10 #include "common.h" 11 12 #include "map.h" 13 #include "posix.h" 14 #include "path.h" 15 #include "pool.h" 16 #include "strmap.h" 17 #include "oid.h" 18 19 /** 20 * Filebuffer methods 21 * 22 * Read whole files into an in-memory buffer for processing 23 */ 24 extern int git_futils_readbuffer(git_buf *obj, const char *path); 25 extern int git_futils_readbuffer_updated( 26 git_buf *obj, const char *path, git_oid *checksum, int *updated); 27 extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len); 28 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 36 extern int git_futils_writebuffer( 37 const git_buf *buf, const char *path, int open_flags, mode_t mode); 38 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 * 45 * All these methods return 0 on success, 46 * or an error code on failure and an error message is set. 47 */ 48 49 /** 50 * Create and open a file, while also 51 * creating all the folders in its path 52 */ 53 extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode); 54 55 /** 56 * Create and open a process-locked file 57 */ 58 extern int git_futils_creat_locked(const char *path, const mode_t mode); 59 60 /** 61 * Create and open a process-locked file, while 62 * also creating all the folders in its path 63 */ 64 extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode); 65 66 /** 67 * Create a path recursively. 68 */ 69 extern int git_futils_mkdir_r(const char *path, const mode_t mode); 70 71 /** 72 * Flags to pass to `git_futils_mkdir`. 73 * 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 79 * * GIT_MKDIR_SKIP_LAST2 says to leave off the last 2 elements of the path 80 * * GIT_MKDIR_VERIFY_DIR says confirm final item is a dir, not just EEXIST 81 * * GIT_MKDIR_REMOVE_FILES says to remove files and recreate dirs 82 * * GIT_MKDIR_REMOVE_SYMLINKS says to remove symlinks and recreate dirs 83 * 84 * Note that the chmod options will be executed even if the directory already 85 * exists, unless GIT_MKDIR_EXCL is given. 86 */ 87 typedef enum { 88 GIT_MKDIR_EXCL = 1, 89 GIT_MKDIR_PATH = 2, 90 GIT_MKDIR_CHMOD = 4, 91 GIT_MKDIR_CHMOD_PATH = 8, 92 GIT_MKDIR_SKIP_LAST = 16, 93 GIT_MKDIR_SKIP_LAST2 = 32, 94 GIT_MKDIR_VERIFY_DIR = 64, 95 GIT_MKDIR_REMOVE_FILES = 128, 96 GIT_MKDIR_REMOVE_SYMLINKS = 256, 97 } git_futils_mkdir_flags; 98 99 struct git_futils_mkdir_perfdata 100 { 101 size_t stat_calls; 102 size_t mkdir_calls; 103 size_t chmod_calls; 104 }; 105 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 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 * 120 * @param path The path to create, relative to base. 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. 124 * @param opts Extended options, or null. 125 * @return 0 on success, else error code 126 */ 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); 128 129 /** 130 * Create a directory or entire path. Similar to `git_futils_mkdir_relative` 131 * without performance data. 132 */ 133 extern int git_futils_mkdir(const char *path, mode_t mode, uint32_t flags); 134 135 /** 136 * Create all the folders required to contain 137 * the full path of a file 138 */ 139 extern int git_futils_mkpath2file(const char *path, const mode_t mode); 140 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 150 * * GIT_RMDIR_REMOVE_BLOCKERS - remove blocking file that causes ENOTDIR 151 * * GIT_RMDIR_SKIP_ROOT - don't remove root directory itself 152 */ 153 typedef enum { 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), 158 GIT_RMDIR_REMOVE_BLOCKERS = (1 << 3), 159 GIT_RMDIR_SKIP_ROOT = (1 << 4), 160 } git_futils_rmdir_flags; 161 162 /** 163 * Remove path and any files and directories beneath it. 164 * 165 * @param path Path to the top level directory to process. 166 * @param base Root for relative path. 167 * @param flags Combination of git_futils_rmdir_flags values 168 * @return 0 on success; -1 on error. 169 */ 170 extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags); 171 172 /** 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. 176 */ 177 extern int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode); 178 179 /** 180 * Move a file on the filesystem, create the 181 * destination path if it doesn't exist 182 */ 183 extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode); 184 185 /** 186 * Copy a file 187 * 188 * The filemode will be used for the newly created file. 189 */ 190 extern int git_futils_cp( 191 const char *from, 192 const char *to, 193 mode_t filemode); 194 195 /** 196 * Set the files atime and mtime to the given time, or the current time 197 * if `ts` is NULL. 198 */ 199 extern int git_futils_touch(const char *path, time_t *when); 200 201 /** 202 * Flags that can be passed to `git_futils_cp_r`. 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. 215 * - GIT_CPDIR_LINK_FILES will try to use hardlinks for the files 216 */ 217 typedef enum { 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), 222 GIT_CPDIR_CHMOD_DIRS = (1u << 4), 223 GIT_CPDIR_SIMPLE_TO_MODE = (1u << 5), 224 GIT_CPDIR_LINK_FILES = (1u << 6), 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 245 /** 246 * Open a file readonly and set error if needed. 247 */ 248 extern int git_futils_open_ro(const char *path); 249 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 255 /** 256 * Get the filesize in bytes of a file 257 */ 258 extern int git_futils_filesize(uint64_t *out, git_file fd); 259 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) 263 264 #define GIT_MODE_PERMS_MASK 0777 265 #define GIT_MODE_TYPE_MASK 0170000 266 #define GIT_MODE_TYPE(MODE) ((MODE) & GIT_MODE_TYPE_MASK) 267 #define GIT_MODE_ISBLOB(MODE) (GIT_MODE_TYPE(MODE) == GIT_MODE_TYPE(GIT_FILEMODE_BLOB)) 268 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 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. 285 * @param len number of bytes to map. 286 * @return 287 * - 0 on success; 288 * - -1 on error. 289 */ 290 extern int git_futils_mmap_ro( 291 git_map *out, 292 git_file fd, 293 off64_t begin, 294 size_t len); 295 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 302 * - 0 on success; 303 * - GIT_ENOTFOUND if not found; 304 * - -1 on an unspecified OS related error. 305 */ 306 extern int git_futils_mmap_ro_file( 307 git_map *out, 308 const char *path); 309 310 /** 311 * Release the memory associated with a previous memory mapping. 312 * @param map the mapping description previously configured. 313 */ 314 extern void git_futils_mmap_free(git_map *map); 315 316 /** 317 * Create a "fake" symlink (text file containing the target path). 318 * 319 * @param target original symlink target 320 * @param path symlink file to be created 321 * @return 0 on success, -1 on error 322 */ 323 extern int git_futils_fake_symlink(const char *target, const char *path); 324 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 */ 331 typedef struct { 332 struct timespec mtime; 333 uint64_t size; 334 unsigned int ino; 335 } git_futils_filestamp; 336 337 /** 338 * Compare stat information for file with reference info. 339 * 340 * This function updates the file stamp to current data for the given path 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 343 * exist. This will not call git_error_set, so you must set the error if you 344 * plan to return an error. 345 * 346 * @param stamp File stamp to be checked 347 * @param path Path to stat and check if changed 348 * @return 0 if up-to-date, 1 if out-of-date, GIT_ENOTFOUND if cannot stat 349 */ 350 extern int git_futils_filestamp_check( 351 git_futils_filestamp *stamp, const char *path); 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 */ 363 extern void git_futils_filestamp_set( 364 git_futils_filestamp *tgt, const git_futils_filestamp *src); 365 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 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 390 #endif 391