Whamcloud - gitweb
New RC 2.16.0-RC5
[fs/lustre-release.git] / lustre / utils / liblustreapi_lseek.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * (C) Copyright (c) 2020, DataDirect Networks Inc, all rights reserved.
7  *
8  * All rights reserved. This program and the accompanying materials
9  * are made available under the terms of the GNU Lesser General Public License
10  * LGPL version 2.1 or (at your discretion) any later version.
11  * LGPL version 2.1 accompanies this distribution, and is available at
12  * http://www.gnu.org/licenses/lgpl-2.1.html
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * LGPL HEADER END
20  */
21 /*
22  * lustre/utils/liblustreapi_lseek.c
23  *
24  * lustreapi library for lseek-related functionality
25  *
26  * Author: Mikhail Pershin <mpershin@whamcloud.com>
27  */
28
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <stdbool.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #ifndef FALLOC_FL_PUNCH_HOLE
37 #include <linux/falloc.h> /* for RHEL7.3 glibc-headers and earlier */
38 #endif
39 #include <sys/syscall.h>
40 #include <sys/ioctl.h>
41 #include <errno.h>
42
43 #include <lustre/lustreapi.h>
44 #include "lustreapi_internal.h"
45
46 /**
47  * Check if file has a hole
48  *
49  * \param fd    file descriptor
50  *
51  * \retval boolean, true if file has a hole, false otherwise
52  */
53 bool llapi_file_is_sparse(int fd)
54 {
55         off_t file_end, hole_off;
56
57         file_end = lseek(fd, 0, SEEK_END);
58         hole_off = lseek(fd, 0, SEEK_HOLE);
59
60         /* Errors are ignored and file is just reported as non-sparse */
61         return file_end > 0 && hole_off >= 0 && hole_off < file_end;
62 }
63
64 /**
65  * Get the first data segment in given extent.
66  *
67  * \param src_fd  source file descriptor
68  * \param offset  offset to start from
69  * \param length  length of data segment found
70  *
71  * \retval next data offset and length on \p length on success.
72  * \retval -errno on failure.
73  */
74 off_t llapi_data_seek(int src_fd, off_t offset, size_t *length)
75 {
76         off_t data_off, hole_off;
77         int rc;
78
79         if (offset < 0) {
80                 rc = -EINVAL;
81                 llapi_error(LLAPI_MSG_ERROR, rc, "wrong offset: %jd",
82                             offset);
83                 return rc;
84         }
85
86         data_off = lseek(src_fd, offset, SEEK_DATA);
87         if (data_off < 0) {
88                 if (errno != ENXIO) {
89                         rc = -errno;
90                         llapi_error(LLAPI_MSG_ERROR, rc,
91                                     "failed SEEK_DATA from %jd",
92                                     offset);
93                         return rc;
94                 }
95                 hole_off = lseek(src_fd, 0, SEEK_END);
96                 if (data_off > hole_off) /* out of file range */
97                         return -ENXIO;
98                 /* no more data in src file, return end of file and zero size
99                  * so caller will know there must be hole up to that offset
100                  */
101                 *length = 0;
102                 return hole_off;
103         }
104
105         hole_off = lseek(src_fd, data_off, SEEK_HOLE);
106         if (hole_off < 0) {
107                 rc = -errno;
108                 llapi_error(LLAPI_MSG_ERROR, rc,
109                             "failed SEEK_HOLE from %jd", data_off);
110                 return rc;
111         }
112         *length = hole_off - data_off;
113         return data_off;
114 }
115
116 /**
117  * Punch hole in a file.
118  *
119  * \param fd     file descriptor
120  * \param start  offset to start from
121  * \param length hole length
122  *
123  * \retval 0 on success.
124  * \retval -errno on failure to punch hole
125  */
126 int llapi_hole_punch(int fd, off_t start, size_t length)
127 {
128         int rc;
129
130         rc = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
131                        start, length);
132         if (rc)
133                 rc = -errno;
134         return rc;
135 }