]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pmdk/src/common/file.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2014-2020, Intel Corporation */
5 * file.c -- file utilities
18 #if !defined(_WIN32) && !defined(__FreeBSD__)
19 #include <sys/sysmacros.h>
22 #include "../libpmem2/config.h"
23 #include "../libpmem2/pmem2_utils.h"
29 #define DEVICE_DAX_ZERO_LEN (2 * MEGABYTE)
32 * util_file_exists -- checks whether file exists
35 util_file_exists(const char *path
)
37 LOG(3, "path \"%s\"", path
);
39 if (os_access(path
, F_OK
) == 0)
42 if (errno
!= ENOENT
) {
43 ERR("!os_access \"%s\"", path
);
48 * ENOENT means that some component of a pathname does not exists.
50 * XXX - we should also call os_access on parent directory and
51 * if this also results in ENOENT -1 should be returned.
53 * The problem is that we would need to use realpath, which fails
54 * if file does not exist.
61 * util_stat_get_type -- checks whether stat structure describes
62 * device dax or a normal file
65 util_stat_get_type(const os_stat_t
*st
)
67 enum pmem2_file_type type
;
69 int ret
= pmem2_get_type_from_stat(st
, &type
);
71 errno
= pmem2_err_to_errno(ret
);
75 if (type
== PMEM2_FTYPE_REG
|| type
== PMEM2_FTYPE_DIR
)
78 if (type
== PMEM2_FTYPE_DEVDAX
)
81 ASSERTinfo(0, "unhandled file type in util_stat_get_type");
86 * util_fd_get_type -- checks whether a file descriptor is associated
87 * with a device dax or a normal file
90 util_fd_get_type(int fd
)
99 if (os_fstat(fd
, &st
) < 0) {
104 return util_stat_get_type(&st
);
109 * util_file_get_type -- checks whether the path points to a device dax,
110 * normal file or non-existent file
113 util_file_get_type(const char *path
)
115 LOG(3, "path \"%s\"", path
);
118 ERR("invalid (NULL) path");
123 int exists
= util_file_exists(path
);
135 if (os_stat(path
, &st
) < 0) {
140 return util_stat_get_type(&st
);
145 * util_file_get_size -- returns size of a file
148 util_file_get_size(const char *path
)
150 LOG(3, "path \"%s\"", path
);
152 int fd
= os_open(path
, O_RDONLY
);
158 ssize_t size
= util_fd_get_size(fd
);
165 * util_fd_get_size -- returns size of a file behind a given file descriptor
168 util_fd_get_size(int fd
)
172 struct pmem2_source
*src
;
176 if ((ret
= pmem2_source_from_fd(&src
, fd
)) != 0) {
177 errno
= pmem2_err_to_errno(ret
);
181 ret
= pmem2_source_size(src
, &size
);
183 pmem2_source_delete(&src
);
186 errno
= pmem2_err_to_errno(ret
);
190 /* size is unsigned, this function returns signed */
191 if (size
>= INT64_MAX
) {
194 "file size (%ld) too big to be represented in 64-bit signed integer",
199 LOG(4, "file length %zu", size
);
200 return (ssize_t
)size
;
204 * util_file_map_whole -- maps the entire file into memory
207 util_file_map_whole(const char *path
)
209 LOG(3, "path \"%s\"", path
);
219 if ((fd
= os_open(path
, flags
)) < 0) {
220 ERR("!open \"%s\"", path
);
224 ssize_t size
= util_fd_get_size(fd
);
226 LOG(2, "cannot determine file length \"%s\"", path
);
230 addr
= util_map(fd
, 0, (size_t)size
, MAP_SHARED
, 0, 0, NULL
);
232 LOG(2, "failed to map entire file \"%s\"", path
);
245 * util_file_zero -- zeroes the specified region of the file
248 util_file_zero(const char *path
, os_off_t off
, size_t len
)
250 LOG(3, "path \"%s\" off %ju len %zu", path
, off
, len
);
260 if ((fd
= os_open(path
, flags
)) < 0) {
261 ERR("!open \"%s\"", path
);
265 ssize_t size
= util_fd_get_size(fd
);
267 LOG(2, "cannot determine file length \"%s\"", path
);
273 LOG(2, "offset beyond file length, %ju > %ju", off
, size
);
278 if ((size_t)off
+ len
> (size_t)size
) {
279 LOG(2, "requested size of write goes beyond the file length, "
280 "%zu > %zu", (size_t)off
+ len
, size
);
281 LOG(4, "adjusting len to %zu", size
- off
);
282 len
= (size_t)(size
- off
);
285 void *addr
= util_map(fd
, 0, (size_t)size
, MAP_SHARED
, 0, 0, NULL
);
287 LOG(2, "failed to map entire file \"%s\"", path
);
292 /* zero initialize the specified region */
293 memset((char *)addr
+ off
, 0, len
);
295 util_unmap(addr
, (size_t)size
);
306 * util_file_pwrite -- writes to a file with an offset
309 util_file_pwrite(const char *path
, const void *buffer
, size_t size
,
312 LOG(3, "path \"%s\" buffer %p size %zu offset %ju",
313 path
, buffer
, size
, offset
);
315 enum file_type type
= util_file_get_type(path
);
319 if (type
== TYPE_NORMAL
) {
320 int fd
= util_file_open(path
, NULL
, 0, O_RDWR
);
322 LOG(2, "failed to open file \"%s\"", path
);
326 ssize_t write_len
= pwrite(fd
, buffer
, size
, offset
);
327 int olderrno
= errno
;
333 ssize_t file_size
= util_file_get_size(path
);
335 LOG(2, "cannot determine file length \"%s\"", path
);
339 size_t max_size
= (size_t)(file_size
- offset
);
340 if (size
> max_size
) {
341 LOG(2, "requested size of write goes beyond the file length, "
342 "%zu > %zu", size
, max_size
);
343 LOG(4, "adjusting size to %zu", max_size
);
347 void *addr
= util_file_map_whole(path
);
349 LOG(2, "failed to map entire file \"%s\"", path
);
353 memcpy(ADDR_SUM(addr
, offset
), buffer
, size
);
354 util_unmap(addr
, (size_t)file_size
);
355 return (ssize_t
)size
;
359 * util_file_pread -- reads from a file with an offset
362 util_file_pread(const char *path
, void *buffer
, size_t size
,
365 LOG(3, "path \"%s\" buffer %p size %zu offset %ju",
366 path
, buffer
, size
, offset
);
368 enum file_type type
= util_file_get_type(path
);
372 if (type
== TYPE_NORMAL
) {
373 int fd
= util_file_open(path
, NULL
, 0, O_RDONLY
);
375 LOG(2, "failed to open file \"%s\"", path
);
379 ssize_t read_len
= pread(fd
, buffer
, size
, offset
);
380 int olderrno
= errno
;
386 ssize_t file_size
= util_file_get_size(path
);
388 LOG(2, "cannot determine file length \"%s\"", path
);
392 size_t max_size
= (size_t)(file_size
- offset
);
393 if (size
> max_size
) {
394 LOG(2, "requested size of read goes beyond the file length, "
395 "%zu > %zu", size
, max_size
);
396 LOG(4, "adjusting size to %zu", max_size
);
400 void *addr
= util_file_map_whole(path
);
402 LOG(2, "failed to map entire file \"%s\"", path
);
406 memcpy(buffer
, ADDR_SUM(addr
, offset
), size
);
407 util_unmap(addr
, (size_t)file_size
);
408 return (ssize_t
)size
;
412 * util_file_create -- create a new memory pool file
415 util_file_create(const char *path
, size_t size
, size_t minsize
)
417 LOG(3, "path \"%s\" size %zu minsize %zu", path
, size
, minsize
);
421 if (size
< minsize
) {
422 ERR("size %zu smaller than %zu", size
, minsize
);
427 if (((os_off_t
)size
) < 0) {
428 ERR("invalid size (%zu) for os_off_t", size
);
435 int flags
= O_RDWR
| O_CREAT
| O_EXCL
;
439 mode
= S_IWRITE
| S_IREAD
;
444 * Create file without any permission. It will be granted once
445 * initialization completes.
447 if ((fd
= os_open(path
, flags
, mode
)) < 0) {
448 ERR("!open \"%s\"", path
);
452 if ((errno
= os_posix_fallocate(fd
, 0, (os_off_t
)size
)) != 0) {
453 ERR("!posix_fallocate \"%s\", %zu", path
, size
);
457 /* for windows we can't flock until after we fallocate */
458 if (os_flock(fd
, OS_LOCK_EX
| OS_LOCK_NB
) < 0) {
459 ERR("!flock \"%s\"", path
);
466 LOG(4, "error clean up");
476 * util_file_open -- open a memory pool file
479 util_file_open(const char *path
, size_t *size
, size_t minsize
, int flags
)
481 LOG(3, "path \"%s\" size %p minsize %zu flags %d", path
, size
, minsize
,
491 if ((fd
= os_open(path
, flags
)) < 0) {
492 ERR("!open \"%s\"", path
);
496 if (os_flock(fd
, OS_LOCK_EX
| OS_LOCK_NB
) < 0) {
497 ERR("!flock \"%s\"", path
);
502 if (size
|| minsize
) {
506 ssize_t actual_size
= util_fd_get_size(fd
);
507 if (actual_size
< 0) {
508 ERR("stat \"%s\": negative size", path
);
513 if ((size_t)actual_size
< minsize
) {
514 ERR("size %zu smaller than %zu",
515 (size_t)actual_size
, minsize
);
521 *size
= (size_t)actual_size
;
522 LOG(4, "actual file size %zu", *size
);
529 if (os_flock(fd
, OS_LOCK_UN
))
530 ERR("!flock unlock");
537 * util_unlink -- unlinks a file or zeroes a device dax
540 util_unlink(const char *path
)
542 LOG(3, "path \"%s\"", path
);
544 enum file_type type
= util_file_get_type(path
);
548 if (type
== TYPE_DEVDAX
) {
549 return util_file_zero(path
, 0, DEVICE_DAX_ZERO_LEN
);
552 /* on Windows we can not unlink Read-Only files */
553 if (os_chmod(path
, S_IREAD
| S_IWRITE
) == -1) {
554 ERR("!chmod \"%s\"", path
);
558 return os_unlink(path
);
563 * util_unlink_flock -- flocks the file and unlinks it
565 * The unlink(2) call on a file which is opened and locked using flock(2)
566 * by different process works on linux. Thus in order to forbid removing a
567 * pool when in use by different process we need to flock(2) the pool files
568 * first before unlinking.
571 util_unlink_flock(const char *path
)
573 LOG(3, "path \"%s\"", path
);
577 * On Windows it is not possible to unlink the
578 * file if it is flocked.
580 return util_unlink(path
);
582 int fd
= util_file_open(path
, NULL
, 0, O_RDONLY
);
584 LOG(2, "failed to open file \"%s\"", path
);
588 int ret
= util_unlink(path
);
597 * util_write_all -- a wrapper for util_write
599 * writes exactly count bytes from buf to file referred to by fd
600 * returns -1 on error, 0 otherwise
603 util_write_all(int fd
, const char *buf
, size_t count
)
608 while (count
> total
) {
609 n_wrote
= util_write(fd
, buf
, count
- total
);
613 buf
+= (size_t)n_wrote
;
614 total
+= (size_t)n_wrote
;