]>
git.proxmox.com Git - libgit2.git/blob - src/fileops.c
6e45ff8a8bc65185d6a77bc2f60444a81551d2d8
2 * Copyright (C) 2009-2012 the libgit2 contributors
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.
11 int git_futils_mkpath2file(const char *file_path
, const mode_t mode
)
14 git_buf target_folder
= GIT_BUF_INIT
;
16 error
= git_path_dirname_r(&target_folder
, file_path
);
17 if (error
< GIT_SUCCESS
) {
18 git_buf_free(&target_folder
);
19 return git__throw(GIT_EINVALIDPATH
, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path
);
25 /* Does the containing folder exist? */
26 if (git_path_isdir(target_folder
.ptr
) != GIT_SUCCESS
)
27 /* Let's create the tree structure */
28 error
= git_futils_mkdir_r(target_folder
.ptr
, NULL
, mode
);
30 git_buf_free(&target_folder
);
34 int git_futils_mktmp(git_buf
*path_out
, const char *filename
)
38 git_buf_sets(path_out
, filename
);
39 git_buf_puts(path_out
, "_git2_XXXXXX");
41 if (git_buf_oom(path_out
))
42 return git__rethrow(git_buf_lasterror(path_out
),
43 "Failed to create temporary file for %s", filename
);
45 if ((fd
= p_mkstemp(path_out
->ptr
)) < 0)
46 return git__throw(GIT_EOSERR
, "Failed to create temporary file %s", path_out
->ptr
);
51 int git_futils_creat_withpath(const char *path
, const mode_t dirmode
, const mode_t mode
)
53 if (git_futils_mkpath2file(path
, dirmode
) < GIT_SUCCESS
)
54 return git__throw(GIT_EOSERR
, "Failed to create file %s", path
);
56 return p_creat(path
, mode
);
59 int git_futils_creat_locked(const char *path
, const mode_t mode
)
61 int fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
| O_EXCL
, mode
);
62 return fd
>= 0 ? fd
: git__throw(GIT_EOSERR
, "Failed to create locked file. Could not open %s", path
);
65 int git_futils_creat_locked_withpath(const char *path
, const mode_t dirmode
, const mode_t mode
)
67 if (git_futils_mkpath2file(path
, dirmode
) < GIT_SUCCESS
)
68 return git__throw(GIT_EOSERR
, "Failed to create locked file %s", path
);
70 return git_futils_creat_locked(path
, mode
);
73 git_off_t
git_futils_filesize(git_file fd
)
82 mode_t
git_futils_canonical_mode(mode_t raw_mode
)
84 if (S_ISREG(raw_mode
))
85 return S_IFREG
| GIT_CANONICAL_PERMS(raw_mode
);
86 else if (S_ISLNK(raw_mode
))
88 else if (S_ISDIR(raw_mode
))
90 else if (S_ISGITLINK(raw_mode
))
96 int git_futils_readbuffer_updated(git_buf
*buf
, const char *path
, time_t *mtime
, int *updated
)
102 assert(buf
&& path
&& *path
);
107 if ((fd
= p_open(path
, O_RDONLY
)) < 0) {
108 return git__throw(GIT_ENOTFOUND
, "Failed to read file '%s': %s", path
, strerror(errno
));
111 if (p_fstat(fd
, &st
) < 0 || S_ISDIR(st
.st_mode
) || !git__is_sizet(st
.st_size
+1)) {
113 return git__throw(GIT_EOSERR
, "Failed to stat file '%s'", path
);
117 * If we were given a time, we only want to read the file if it
120 if (mtime
!= NULL
&& *mtime
>= st
.st_mtime
) {
126 *mtime
= st
.st_mtime
;
128 len
= (size_t) st
.st_size
;
132 if (git_buf_grow(buf
, len
+ 1) < 0) {
137 buf
->ptr
[len
] = '\0';
140 ssize_t read_size
= p_read(fd
, buf
->ptr
, len
);
144 return git__throw(GIT_EOSERR
, "Failed to read from FD");
148 buf
->size
+= read_size
;
154 *mtime
= st
.st_mtime
;
162 int git_futils_readbuffer(git_buf
*buf
, const char *path
)
164 return git_futils_readbuffer_updated(buf
, path
, NULL
, NULL
);
167 int git_futils_mv_withpath(const char *from
, const char *to
, const mode_t dirmode
)
169 if (git_futils_mkpath2file(to
, dirmode
) < GIT_SUCCESS
)
170 return GIT_EOSERR
; /* The callee already takes care of setting the correct error message. */
172 return p_rename(from
, to
); /* The callee already takes care of setting the correct error message. */
175 int git_futils_mmap_ro(git_map
*out
, git_file fd
, git_off_t begin
, size_t len
)
177 return p_mmap(out
, len
, GIT_PROT_READ
, GIT_MAP_SHARED
, fd
, begin
);
180 int git_futils_mmap_ro_file(git_map
*out
, const char *path
)
182 git_file fd
= p_open(path
, O_RDONLY
/* | O_NOATIME */);
183 size_t len
= git_futils_filesize(fd
);
184 int result
= git_futils_mmap_ro(out
, fd
, 0, len
);
189 void git_futils_mmap_free(git_map
*out
)
194 int git_futils_mkdir_r(const char *path
, const char *base
, const mode_t mode
)
196 int error
, root_path_offset
;
197 git_buf make_path
= GIT_BUF_INIT
;
202 start
= strlen(base
);
203 error
= git_buf_joinpath(&make_path
, base
, path
);
206 error
= git_buf_puts(&make_path
, path
);
208 if (error
< GIT_SUCCESS
)
209 return git__rethrow(error
, "Failed to create `%s` tree structure", path
);
211 pp
= make_path
.ptr
+ start
;
213 root_path_offset
= git_path_root(make_path
.ptr
);
214 if (root_path_offset
> 0)
215 pp
+= root_path_offset
; /* On Windows, will skip the drive name (eg. C: or D:) */
217 while (error
== GIT_SUCCESS
&& (sp
= strchr(pp
, '/')) != NULL
) {
218 if (sp
!= pp
&& git_path_isdir(make_path
.ptr
) < GIT_SUCCESS
) {
220 error
= p_mkdir(make_path
.ptr
, mode
);
222 /* Do not choke while trying to recreate an existing directory */
232 if (*pp
!= '\0' && error
== GIT_SUCCESS
) {
233 error
= p_mkdir(make_path
.ptr
, mode
);
238 git_buf_free(&make_path
);
240 if (error
< GIT_SUCCESS
)
241 return git__throw(error
, "Failed to recursively create `%s` tree structure", path
);
246 static int _rmdir_recurs_foreach(void *opaque
, git_buf
*path
)
248 int error
= GIT_SUCCESS
;
249 int force
= *(int *)opaque
;
251 if (git_path_isdir(path
->ptr
) == GIT_SUCCESS
) {
252 error
= git_path_direach(path
, _rmdir_recurs_foreach
, opaque
);
253 if (error
< GIT_SUCCESS
)
254 return git__rethrow(error
, "Failed to remove directory `%s`", path
->ptr
);
255 return p_rmdir(path
->ptr
);
258 return p_unlink(path
->ptr
);
261 return git__rethrow(error
, "Failed to remove directory. `%s` is not empty", path
->ptr
);
264 int git_futils_rmdir_r(const char *path
, int force
)
267 git_buf p
= GIT_BUF_INIT
;
269 error
= git_buf_sets(&p
, path
);
270 if (error
== GIT_SUCCESS
)
271 error
= _rmdir_recurs_foreach(&force
, &p
);
276 int git_futils_find_global_file(git_buf
*path
, const char *filename
)
279 const char *home
= getenv("HOME");
283 home
= getenv("USERPROFILE");
287 return git__throw(GIT_EOSERR
, "Failed to open global %s file. "
288 "Cannot locate the user's home directory.", filename
);
290 if ((error
= git_buf_joinpath(path
, home
, filename
)) < GIT_SUCCESS
)
293 if (git_path_exists(path
->ptr
) < GIT_SUCCESS
) {
295 return GIT_ENOTFOUND
;
307 static const win32_path
*win32_system_root(void)
309 static win32_path s_root
= { 0, 0 };
311 if (s_root
.path
== NULL
) {
312 const wchar_t *root_tmpl
= L
"%PROGRAMFILES%\\Git\\etc\\";
314 s_root
.len
= ExpandEnvironmentStringsW(root_tmpl
, NULL
, 0);
316 if (s_root
.len
<= 0) {
317 git__throw(GIT_EOSERR
, "Failed to expand environment strings");
321 s_root
.path
= git__calloc(s_root
.len
, sizeof(wchar_t));
322 if (s_root
.path
== NULL
)
325 if (ExpandEnvironmentStringsW(root_tmpl
, s_root
.path
, s_root
.len
) != s_root
.len
) {
326 git__throw(GIT_EOSERR
, "Failed to expand environment strings");
327 git__free(s_root
.path
);
336 static int win32_find_system_file(git_buf
*path
, const char *filename
)
338 int error
= GIT_SUCCESS
;
339 const win32_path
*root
= win32_system_root();
341 wchar_t *file_utf16
= NULL
, *scan
;
342 char *file_utf8
= NULL
;
344 if (!root
|| !filename
|| (len
= strlen(filename
)) == 0)
345 return GIT_ENOTFOUND
;
347 /* allocate space for wchar_t path to file */
348 file_utf16
= git__calloc(root
->len
+ len
+ 2, sizeof(wchar_t));
352 /* append root + '\\' + filename as wchar_t */
353 memcpy(file_utf16
, root
->path
, root
->len
* sizeof(wchar_t));
355 if (*filename
== '/' || *filename
== '\\')
358 if (gitwin_append_utf16(file_utf16
+ root
->len
- 1, filename
, len
+ 1) !=
360 error
= git__throw(GIT_EOSERR
, "Failed to build file path");
364 for (scan
= file_utf16
; *scan
; scan
++)
369 if (_waccess(file_utf16
, F_OK
) < 0) {
370 error
= GIT_ENOTFOUND
;
374 /* convert to utf8 */
375 if ((file_utf8
= gitwin_from_utf16(file_utf16
)) == NULL
)
379 git_path_mkposix(file_utf8
);
380 git_buf_attach(path
, file_utf8
, 0);
384 git__free(file_utf16
);
390 int git_futils_find_system_file(git_buf
*path
, const char *filename
)
392 if (git_buf_joinpath(path
, "/etc", filename
) < GIT_SUCCESS
)
393 return git_buf_lasterror(path
);
395 if (git_path_exists(path
->ptr
) == GIT_SUCCESS
)
401 return win32_find_system_file(path
, filename
);
403 return GIT_ENOTFOUND
;