]>
git.proxmox.com Git - libgit2.git/blob - src/fileops.c
2 * Copyright (C) 2009-2011 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 int git_futils_readbuffer_updated(git_fbuffer
*obj
, const char *path
, time_t *mtime
, int *updated
)
89 assert(obj
&& path
&& *path
);
94 if (p_stat(path
, &st
) < 0)
95 return git__throw(GIT_ENOTFOUND
, "Failed to stat file %s", path
);
97 if (S_ISDIR(st
.st_mode
))
98 return git__throw(GIT_ERROR
, "Can't read a dir into a buffer");
101 * If we were given a time, we only want to read the file if it
104 if (mtime
!= NULL
&& *mtime
>= st
.st_mtime
)
108 *mtime
= st
.st_mtime
;
109 if (!git__is_sizet(st
.st_size
+1))
110 return git__throw(GIT_ERROR
, "Failed to read file `%s`. An error occured while calculating its size", path
);
112 len
= (size_t) st
.st_size
;
114 if ((fd
= p_open(path
, O_RDONLY
)) < 0)
115 return git__throw(GIT_EOSERR
, "Failed to open %s for reading", path
);
117 if ((buff
= git__malloc(len
+ 1)) == NULL
) {
122 if (p_read(fd
, buff
, len
) < 0) {
125 return git__throw(GIT_ERROR
, "Failed to read file `%s`", path
);
132 *mtime
= st
.st_mtime
;
142 int git_futils_readbuffer(git_fbuffer
*obj
, const char *path
)
144 return git_futils_readbuffer_updated(obj
, path
, NULL
, NULL
);
147 void git_futils_fbuffer_rtrim(git_fbuffer
*obj
)
149 unsigned char *buff
= obj
->data
;
150 while (obj
->len
> 0 && isspace(buff
[obj
->len
- 1]))
152 buff
[obj
->len
] = '\0';
155 void git_futils_freebuffer(git_fbuffer
*obj
)
158 git__free(obj
->data
);
163 int git_futils_mv_withpath(const char *from
, const char *to
, const mode_t dirmode
)
165 if (git_futils_mkpath2file(to
, dirmode
) < GIT_SUCCESS
)
166 return GIT_EOSERR
; /* The callee already takes care of setting the correct error message. */
168 return p_rename(from
, to
); /* The callee already takes care of setting the correct error message. */
171 int git_futils_mmap_ro(git_map
*out
, git_file fd
, git_off_t begin
, size_t len
)
173 return p_mmap(out
, len
, GIT_PROT_READ
, GIT_MAP_SHARED
, fd
, begin
);
176 void git_futils_mmap_free(git_map
*out
)
181 int git_futils_mkdir_r(const char *path
, const char *base
, const mode_t mode
)
183 int error
, root_path_offset
;
184 git_buf make_path
= GIT_BUF_INIT
;
189 start
= strlen(base
);
190 error
= git_buf_joinpath(&make_path
, base
, path
);
193 error
= git_buf_puts(&make_path
, path
);
195 if (error
< GIT_SUCCESS
)
196 return git__rethrow(error
, "Failed to create `%s` tree structure", path
);
198 pp
= make_path
.ptr
+ start
;
200 root_path_offset
= git_path_root(make_path
.ptr
);
201 if (root_path_offset
> 0)
202 pp
+= root_path_offset
; /* On Windows, will skip the drive name (eg. C: or D:) */
204 while (error
== GIT_SUCCESS
&& (sp
= strchr(pp
, '/')) != NULL
) {
205 if (sp
!= pp
&& git_path_isdir(make_path
.ptr
) < GIT_SUCCESS
) {
207 error
= p_mkdir(make_path
.ptr
, mode
);
209 /* Do not choke while trying to recreate an existing directory */
219 if (*pp
!= '\0' && error
== GIT_SUCCESS
) {
220 error
= p_mkdir(make_path
.ptr
, mode
);
225 git_buf_free(&make_path
);
227 if (error
< GIT_SUCCESS
)
228 return git__throw(error
, "Failed to recursively create `%s` tree structure", path
);
233 static int _rmdir_recurs_foreach(void *opaque
, git_buf
*path
)
235 int error
= GIT_SUCCESS
;
236 int force
= *(int *)opaque
;
238 if (git_path_isdir(path
->ptr
) == GIT_SUCCESS
) {
239 error
= git_path_direach(path
, _rmdir_recurs_foreach
, opaque
);
240 if (error
< GIT_SUCCESS
)
241 return git__rethrow(error
, "Failed to remove directory `%s`", path
->ptr
);
242 return p_rmdir(path
->ptr
);
245 return p_unlink(path
->ptr
);
248 return git__rethrow(error
, "Failed to remove directory. `%s` is not empty", path
->ptr
);
251 int git_futils_rmdir_r(const char *path
, int force
)
254 git_buf p
= GIT_BUF_INIT
;
256 error
= git_buf_sets(&p
, path
);
257 if (error
== GIT_SUCCESS
)
258 error
= _rmdir_recurs_foreach(&force
, &p
);
263 int git_futils_find_global_file(git_buf
*path
, const char *filename
)
266 const char *home
= getenv("HOME");
270 home
= getenv("USERPROFILE");
274 return git__throw(GIT_EOSERR
, "Failed to open global %s file. "
275 "Cannot locate the user's home directory.", filename
);
277 if ((error
= git_buf_joinpath(path
, home
, filename
)) < GIT_SUCCESS
)
280 if (git_path_exists(path
->ptr
) < GIT_SUCCESS
) {
282 return GIT_ENOTFOUND
;
294 static const win32_path
*win32_system_root(void)
296 static win32_path s_root
= { 0, 0 };
298 if (s_root
.path
== NULL
) {
299 const wchar_t *root_tmpl
= L
"%PROGRAMFILES%\\Git\\etc\\";
301 s_root
.len
= ExpandEnvironmentStringsW(root_tmpl
, NULL
, 0);
303 if (s_root
.len
<= 0) {
304 git__throw(GIT_EOSERR
, "Failed to expand environment strings");
308 s_root
.path
= git__calloc(s_root
.len
, sizeof(wchar_t));
309 if (s_root
.path
== NULL
)
312 if (ExpandEnvironmentStringsW(root_tmpl
, s_root
.path
, s_root
.len
) != s_root
.len
) {
313 git__throw(GIT_EOSERR
, "Failed to expand environment strings");
314 git__free(s_root
.path
);
323 static int win32_find_system_file(git_buf
*path
, const char *filename
)
325 int error
= GIT_SUCCESS
;
326 const win32_path
*root
= win32_system_root();
328 wchar_t *file_utf16
= NULL
, *scan
;
329 char *file_utf8
= NULL
;
331 if (!root
|| !filename
|| (len
= strlen(filename
)) == 0)
332 return GIT_ENOTFOUND
;
334 /* allocate space for wchar_t path to file */
335 file_utf16
= git__calloc(root
->len
+ len
+ 2, sizeof(wchar_t));
339 /* append root + '\\' + filename as wchar_t */
340 memcpy(file_utf16
, root
->path
, root
->len
* sizeof(wchar_t));
342 if (*filename
== '/' || *filename
== '\\')
345 if (gitwin_append_utf16(file_utf16
+ root
->len
- 1, filename
, len
+ 1) !=
347 error
= git__throw(GIT_EOSERR
, "Failed to build file path");
351 for (scan
= file_utf16
; *scan
; scan
++)
356 if (_waccess(file_utf16
, F_OK
) < 0) {
357 error
= GIT_ENOTFOUND
;
361 /* convert to utf8 */
362 if ((file_utf8
= gitwin_from_utf16(file_utf16
)) == NULL
)
366 git_path_mkposix(file_utf8
);
367 git_buf_attach(path
, file_utf8
, 0);
371 git__free(file_utf16
);
377 int git_futils_find_system_file(git_buf
*path
, const char *filename
)
379 if (git_buf_joinpath(path
, "/etc", filename
) < GIT_SUCCESS
)
380 return git_buf_lasterror(path
);
382 if (git_path_exists(path
->ptr
) == GIT_SUCCESS
)
388 return win32_find_system_file(path
, filename
);
390 return GIT_ENOTFOUND
;