1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker * Copyright (C) 2018 HUAWEI, Inc.
4*33b1fccfSAndroid Build Coastguard Worker * http://www.huawei.com/
5*33b1fccfSAndroid Build Coastguard Worker * Created by Li Guifu <[email protected]>
6*33b1fccfSAndroid Build Coastguard Worker */
7*33b1fccfSAndroid Build Coastguard Worker #ifndef _LARGEFILE64_SOURCE
8*33b1fccfSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
9*33b1fccfSAndroid Build Coastguard Worker #endif
10*33b1fccfSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
11*33b1fccfSAndroid Build Coastguard Worker #define _GNU_SOURCE
12*33b1fccfSAndroid Build Coastguard Worker #endif
13*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
14*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
15*33b1fccfSAndroid Build Coastguard Worker #include <sys/ioctl.h>
16*33b1fccfSAndroid Build Coastguard Worker #include "erofs/internal.h"
17*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LINUX_FS_H
18*33b1fccfSAndroid Build Coastguard Worker #include <linux/fs.h>
19*33b1fccfSAndroid Build Coastguard Worker #endif
20*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LINUX_FALLOC_H
21*33b1fccfSAndroid Build Coastguard Worker #include <linux/falloc.h>
22*33b1fccfSAndroid Build Coastguard Worker #endif
23*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_SYS_STATFS_H
24*33b1fccfSAndroid Build Coastguard Worker #include <sys/statfs.h>
25*33b1fccfSAndroid Build Coastguard Worker #endif
26*33b1fccfSAndroid Build Coastguard Worker #define EROFS_MODNAME "erofs_io"
27*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
28*33b1fccfSAndroid Build Coastguard Worker
erofs_io_fstat(struct erofs_vfile * vf,struct stat * buf)29*33b1fccfSAndroid Build Coastguard Worker int erofs_io_fstat(struct erofs_vfile *vf, struct stat *buf)
30*33b1fccfSAndroid Build Coastguard Worker {
31*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(cfg.c_dry_run)) {
32*33b1fccfSAndroid Build Coastguard Worker buf->st_size = 0;
33*33b1fccfSAndroid Build Coastguard Worker buf->st_mode = S_IFREG | 0777;
34*33b1fccfSAndroid Build Coastguard Worker return 0;
35*33b1fccfSAndroid Build Coastguard Worker }
36*33b1fccfSAndroid Build Coastguard Worker
37*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
38*33b1fccfSAndroid Build Coastguard Worker return vf->ops->fstat(vf, buf);
39*33b1fccfSAndroid Build Coastguard Worker return fstat(vf->fd, buf);
40*33b1fccfSAndroid Build Coastguard Worker }
41*33b1fccfSAndroid Build Coastguard Worker
erofs_io_pwrite(struct erofs_vfile * vf,const void * buf,u64 pos,size_t len)42*33b1fccfSAndroid Build Coastguard Worker ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void *buf,
43*33b1fccfSAndroid Build Coastguard Worker u64 pos, size_t len)
44*33b1fccfSAndroid Build Coastguard Worker {
45*33b1fccfSAndroid Build Coastguard Worker ssize_t ret, written = 0;
46*33b1fccfSAndroid Build Coastguard Worker
47*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(cfg.c_dry_run))
48*33b1fccfSAndroid Build Coastguard Worker return 0;
49*33b1fccfSAndroid Build Coastguard Worker
50*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
51*33b1fccfSAndroid Build Coastguard Worker return vf->ops->pwrite(vf, buf, pos, len);
52*33b1fccfSAndroid Build Coastguard Worker
53*33b1fccfSAndroid Build Coastguard Worker pos += vf->offset;
54*33b1fccfSAndroid Build Coastguard Worker do {
55*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PWRITE64
56*33b1fccfSAndroid Build Coastguard Worker ret = pwrite64(vf->fd, buf, len, (off64_t)pos);
57*33b1fccfSAndroid Build Coastguard Worker #else
58*33b1fccfSAndroid Build Coastguard Worker ret = pwrite(vf->fd, buf, len, (off_t)pos);
59*33b1fccfSAndroid Build Coastguard Worker #endif
60*33b1fccfSAndroid Build Coastguard Worker if (ret <= 0) {
61*33b1fccfSAndroid Build Coastguard Worker if (!ret)
62*33b1fccfSAndroid Build Coastguard Worker break;
63*33b1fccfSAndroid Build Coastguard Worker if (errno != EINTR) {
64*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to write: %s", strerror(errno));
65*33b1fccfSAndroid Build Coastguard Worker return -errno;
66*33b1fccfSAndroid Build Coastguard Worker }
67*33b1fccfSAndroid Build Coastguard Worker ret = 0;
68*33b1fccfSAndroid Build Coastguard Worker }
69*33b1fccfSAndroid Build Coastguard Worker buf += ret;
70*33b1fccfSAndroid Build Coastguard Worker pos += ret;
71*33b1fccfSAndroid Build Coastguard Worker written += ret;
72*33b1fccfSAndroid Build Coastguard Worker } while (written < len);
73*33b1fccfSAndroid Build Coastguard Worker
74*33b1fccfSAndroid Build Coastguard Worker return written;
75*33b1fccfSAndroid Build Coastguard Worker }
76*33b1fccfSAndroid Build Coastguard Worker
erofs_io_fsync(struct erofs_vfile * vf)77*33b1fccfSAndroid Build Coastguard Worker int erofs_io_fsync(struct erofs_vfile *vf)
78*33b1fccfSAndroid Build Coastguard Worker {
79*33b1fccfSAndroid Build Coastguard Worker int ret;
80*33b1fccfSAndroid Build Coastguard Worker
81*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(cfg.c_dry_run))
82*33b1fccfSAndroid Build Coastguard Worker return 0;
83*33b1fccfSAndroid Build Coastguard Worker
84*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
85*33b1fccfSAndroid Build Coastguard Worker return vf->ops->fsync(vf);
86*33b1fccfSAndroid Build Coastguard Worker
87*33b1fccfSAndroid Build Coastguard Worker ret = fsync(vf->fd);
88*33b1fccfSAndroid Build Coastguard Worker if (ret) {
89*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to fsync(!): %s", strerror(errno));
90*33b1fccfSAndroid Build Coastguard Worker return -errno;
91*33b1fccfSAndroid Build Coastguard Worker }
92*33b1fccfSAndroid Build Coastguard Worker return 0;
93*33b1fccfSAndroid Build Coastguard Worker }
94*33b1fccfSAndroid Build Coastguard Worker
erofs_io_fallocate(struct erofs_vfile * vf,u64 offset,size_t len,bool zeroout)95*33b1fccfSAndroid Build Coastguard Worker ssize_t erofs_io_fallocate(struct erofs_vfile *vf, u64 offset,
96*33b1fccfSAndroid Build Coastguard Worker size_t len, bool zeroout)
97*33b1fccfSAndroid Build Coastguard Worker {
98*33b1fccfSAndroid Build Coastguard Worker static const char zero[EROFS_MAX_BLOCK_SIZE] = {0};
99*33b1fccfSAndroid Build Coastguard Worker ssize_t ret;
100*33b1fccfSAndroid Build Coastguard Worker
101*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(cfg.c_dry_run))
102*33b1fccfSAndroid Build Coastguard Worker return 0;
103*33b1fccfSAndroid Build Coastguard Worker
104*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
105*33b1fccfSAndroid Build Coastguard Worker return vf->ops->fallocate(vf, offset, len, zeroout);
106*33b1fccfSAndroid Build Coastguard Worker
107*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
108*33b1fccfSAndroid Build Coastguard Worker if (!zeroout && fallocate(vf->fd, FALLOC_FL_PUNCH_HOLE |
109*33b1fccfSAndroid Build Coastguard Worker FALLOC_FL_KEEP_SIZE, offset + vf->offset, len) >= 0)
110*33b1fccfSAndroid Build Coastguard Worker return 0;
111*33b1fccfSAndroid Build Coastguard Worker #endif
112*33b1fccfSAndroid Build Coastguard Worker while (len > EROFS_MAX_BLOCK_SIZE) {
113*33b1fccfSAndroid Build Coastguard Worker ret = erofs_io_pwrite(vf, zero, offset, EROFS_MAX_BLOCK_SIZE);
114*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
115*33b1fccfSAndroid Build Coastguard Worker return ret;
116*33b1fccfSAndroid Build Coastguard Worker len -= ret;
117*33b1fccfSAndroid Build Coastguard Worker offset += ret;
118*33b1fccfSAndroid Build Coastguard Worker }
119*33b1fccfSAndroid Build Coastguard Worker return erofs_io_pwrite(vf, zero, offset, len) == len ? 0 : -EIO;
120*33b1fccfSAndroid Build Coastguard Worker }
121*33b1fccfSAndroid Build Coastguard Worker
erofs_io_ftruncate(struct erofs_vfile * vf,u64 length)122*33b1fccfSAndroid Build Coastguard Worker int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length)
123*33b1fccfSAndroid Build Coastguard Worker {
124*33b1fccfSAndroid Build Coastguard Worker int ret;
125*33b1fccfSAndroid Build Coastguard Worker struct stat st;
126*33b1fccfSAndroid Build Coastguard Worker
127*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(cfg.c_dry_run))
128*33b1fccfSAndroid Build Coastguard Worker return 0;
129*33b1fccfSAndroid Build Coastguard Worker
130*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
131*33b1fccfSAndroid Build Coastguard Worker return vf->ops->ftruncate(vf, length);
132*33b1fccfSAndroid Build Coastguard Worker
133*33b1fccfSAndroid Build Coastguard Worker ret = fstat(vf->fd, &st);
134*33b1fccfSAndroid Build Coastguard Worker if (ret) {
135*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to fstat: %s", strerror(errno));
136*33b1fccfSAndroid Build Coastguard Worker return -errno;
137*33b1fccfSAndroid Build Coastguard Worker }
138*33b1fccfSAndroid Build Coastguard Worker length += vf->offset;
139*33b1fccfSAndroid Build Coastguard Worker if (S_ISBLK(st.st_mode) || st.st_size == length)
140*33b1fccfSAndroid Build Coastguard Worker return 0;
141*33b1fccfSAndroid Build Coastguard Worker return ftruncate(vf->fd, length);
142*33b1fccfSAndroid Build Coastguard Worker }
143*33b1fccfSAndroid Build Coastguard Worker
erofs_io_pread(struct erofs_vfile * vf,void * buf,u64 pos,size_t len)144*33b1fccfSAndroid Build Coastguard Worker ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 pos, size_t len)
145*33b1fccfSAndroid Build Coastguard Worker {
146*33b1fccfSAndroid Build Coastguard Worker ssize_t ret, read = 0;
147*33b1fccfSAndroid Build Coastguard Worker
148*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(cfg.c_dry_run))
149*33b1fccfSAndroid Build Coastguard Worker return 0;
150*33b1fccfSAndroid Build Coastguard Worker
151*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
152*33b1fccfSAndroid Build Coastguard Worker return vf->ops->pread(vf, buf, pos, len);
153*33b1fccfSAndroid Build Coastguard Worker
154*33b1fccfSAndroid Build Coastguard Worker pos += vf->offset;
155*33b1fccfSAndroid Build Coastguard Worker do {
156*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PREAD64
157*33b1fccfSAndroid Build Coastguard Worker ret = pread64(vf->fd, buf, len, (off64_t)pos);
158*33b1fccfSAndroid Build Coastguard Worker #else
159*33b1fccfSAndroid Build Coastguard Worker ret = pread(vf->fd, buf, len, (off_t)pos);
160*33b1fccfSAndroid Build Coastguard Worker #endif
161*33b1fccfSAndroid Build Coastguard Worker if (ret <= 0) {
162*33b1fccfSAndroid Build Coastguard Worker if (!ret)
163*33b1fccfSAndroid Build Coastguard Worker break;
164*33b1fccfSAndroid Build Coastguard Worker if (errno != EINTR) {
165*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read: %s", strerror(errno));
166*33b1fccfSAndroid Build Coastguard Worker return -errno;
167*33b1fccfSAndroid Build Coastguard Worker }
168*33b1fccfSAndroid Build Coastguard Worker ret = 0;
169*33b1fccfSAndroid Build Coastguard Worker }
170*33b1fccfSAndroid Build Coastguard Worker pos += ret;
171*33b1fccfSAndroid Build Coastguard Worker buf += ret;
172*33b1fccfSAndroid Build Coastguard Worker read += ret;
173*33b1fccfSAndroid Build Coastguard Worker } while (read < len);
174*33b1fccfSAndroid Build Coastguard Worker
175*33b1fccfSAndroid Build Coastguard Worker return read;
176*33b1fccfSAndroid Build Coastguard Worker }
177*33b1fccfSAndroid Build Coastguard Worker
erofs_get_bdev_size(int fd,u64 * bytes)178*33b1fccfSAndroid Build Coastguard Worker static int erofs_get_bdev_size(int fd, u64 *bytes)
179*33b1fccfSAndroid Build Coastguard Worker {
180*33b1fccfSAndroid Build Coastguard Worker errno = ENOTSUP;
181*33b1fccfSAndroid Build Coastguard Worker #ifdef BLKGETSIZE64
182*33b1fccfSAndroid Build Coastguard Worker if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
183*33b1fccfSAndroid Build Coastguard Worker return 0;
184*33b1fccfSAndroid Build Coastguard Worker #endif
185*33b1fccfSAndroid Build Coastguard Worker
186*33b1fccfSAndroid Build Coastguard Worker #ifdef BLKGETSIZE
187*33b1fccfSAndroid Build Coastguard Worker {
188*33b1fccfSAndroid Build Coastguard Worker unsigned long size;
189*33b1fccfSAndroid Build Coastguard Worker if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
190*33b1fccfSAndroid Build Coastguard Worker *bytes = ((u64)size << 9);
191*33b1fccfSAndroid Build Coastguard Worker return 0;
192*33b1fccfSAndroid Build Coastguard Worker }
193*33b1fccfSAndroid Build Coastguard Worker }
194*33b1fccfSAndroid Build Coastguard Worker #endif
195*33b1fccfSAndroid Build Coastguard Worker return -errno;
196*33b1fccfSAndroid Build Coastguard Worker }
197*33b1fccfSAndroid Build Coastguard Worker
198*33b1fccfSAndroid Build Coastguard Worker #if defined(__linux__) && !defined(BLKDISCARD)
199*33b1fccfSAndroid Build Coastguard Worker #define BLKDISCARD _IO(0x12, 119)
200*33b1fccfSAndroid Build Coastguard Worker #endif
201*33b1fccfSAndroid Build Coastguard Worker
erofs_bdev_discard(int fd,u64 block,u64 count)202*33b1fccfSAndroid Build Coastguard Worker static int erofs_bdev_discard(int fd, u64 block, u64 count)
203*33b1fccfSAndroid Build Coastguard Worker {
204*33b1fccfSAndroid Build Coastguard Worker #ifdef BLKDISCARD
205*33b1fccfSAndroid Build Coastguard Worker u64 range[2] = { block, count };
206*33b1fccfSAndroid Build Coastguard Worker
207*33b1fccfSAndroid Build Coastguard Worker return ioctl(fd, BLKDISCARD, &range);
208*33b1fccfSAndroid Build Coastguard Worker #else
209*33b1fccfSAndroid Build Coastguard Worker return -EOPNOTSUPP;
210*33b1fccfSAndroid Build Coastguard Worker #endif
211*33b1fccfSAndroid Build Coastguard Worker }
212*33b1fccfSAndroid Build Coastguard Worker
erofs_dev_open(struct erofs_sb_info * sbi,const char * dev,int flags)213*33b1fccfSAndroid Build Coastguard Worker int erofs_dev_open(struct erofs_sb_info *sbi, const char *dev, int flags)
214*33b1fccfSAndroid Build Coastguard Worker {
215*33b1fccfSAndroid Build Coastguard Worker bool ro = (flags & O_ACCMODE) == O_RDONLY;
216*33b1fccfSAndroid Build Coastguard Worker bool truncate = flags & O_TRUNC;
217*33b1fccfSAndroid Build Coastguard Worker struct stat st;
218*33b1fccfSAndroid Build Coastguard Worker int fd, ret;
219*33b1fccfSAndroid Build Coastguard Worker
220*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_SYS_STATFS_H) && defined(HAVE_FSTATFS)
221*33b1fccfSAndroid Build Coastguard Worker bool again = false;
222*33b1fccfSAndroid Build Coastguard Worker
223*33b1fccfSAndroid Build Coastguard Worker repeat:
224*33b1fccfSAndroid Build Coastguard Worker #endif
225*33b1fccfSAndroid Build Coastguard Worker fd = open(dev, (ro ? O_RDONLY : O_RDWR | O_CREAT) | O_BINARY, 0644);
226*33b1fccfSAndroid Build Coastguard Worker if (fd < 0) {
227*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to open %s: %s", dev, strerror(errno));
228*33b1fccfSAndroid Build Coastguard Worker return -errno;
229*33b1fccfSAndroid Build Coastguard Worker }
230*33b1fccfSAndroid Build Coastguard Worker
231*33b1fccfSAndroid Build Coastguard Worker if (ro || !truncate)
232*33b1fccfSAndroid Build Coastguard Worker goto out;
233*33b1fccfSAndroid Build Coastguard Worker
234*33b1fccfSAndroid Build Coastguard Worker ret = fstat(fd, &st);
235*33b1fccfSAndroid Build Coastguard Worker if (ret) {
236*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to fstat(%s): %s", dev, strerror(errno));
237*33b1fccfSAndroid Build Coastguard Worker close(fd);
238*33b1fccfSAndroid Build Coastguard Worker return -errno;
239*33b1fccfSAndroid Build Coastguard Worker }
240*33b1fccfSAndroid Build Coastguard Worker
241*33b1fccfSAndroid Build Coastguard Worker switch (st.st_mode & S_IFMT) {
242*33b1fccfSAndroid Build Coastguard Worker case S_IFBLK:
243*33b1fccfSAndroid Build Coastguard Worker ret = erofs_get_bdev_size(fd, &sbi->devsz);
244*33b1fccfSAndroid Build Coastguard Worker if (ret) {
245*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to get block device size(%s): %s",
246*33b1fccfSAndroid Build Coastguard Worker dev, strerror(errno));
247*33b1fccfSAndroid Build Coastguard Worker close(fd);
248*33b1fccfSAndroid Build Coastguard Worker return ret;
249*33b1fccfSAndroid Build Coastguard Worker }
250*33b1fccfSAndroid Build Coastguard Worker sbi->devsz = round_down(sbi->devsz, erofs_blksiz(sbi));
251*33b1fccfSAndroid Build Coastguard Worker ret = erofs_bdev_discard(fd, 0, sbi->devsz);
252*33b1fccfSAndroid Build Coastguard Worker if (ret)
253*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to erase block device(%s): %s",
254*33b1fccfSAndroid Build Coastguard Worker dev, erofs_strerror(ret));
255*33b1fccfSAndroid Build Coastguard Worker break;
256*33b1fccfSAndroid Build Coastguard Worker case S_IFREG:
257*33b1fccfSAndroid Build Coastguard Worker if (st.st_size) {
258*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_SYS_STATFS_H) && defined(HAVE_FSTATFS)
259*33b1fccfSAndroid Build Coastguard Worker struct statfs stfs;
260*33b1fccfSAndroid Build Coastguard Worker
261*33b1fccfSAndroid Build Coastguard Worker if (again) {
262*33b1fccfSAndroid Build Coastguard Worker close(fd);
263*33b1fccfSAndroid Build Coastguard Worker return -ENOTEMPTY;
264*33b1fccfSAndroid Build Coastguard Worker }
265*33b1fccfSAndroid Build Coastguard Worker
266*33b1fccfSAndroid Build Coastguard Worker /*
267*33b1fccfSAndroid Build Coastguard Worker * fses like EXT4 and BTRFS will flush dirty blocks
268*33b1fccfSAndroid Build Coastguard Worker * after truncate(0) even after the writeback happens
269*33b1fccfSAndroid Build Coastguard Worker * (see kernel commit 7d8f9f7d150d and ccd2506bd431),
270*33b1fccfSAndroid Build Coastguard Worker * which is NOT our intention. Let's work around this.
271*33b1fccfSAndroid Build Coastguard Worker */
272*33b1fccfSAndroid Build Coastguard Worker if (!fstatfs(fd, &stfs) && (stfs.f_type == 0xEF53 ||
273*33b1fccfSAndroid Build Coastguard Worker stfs.f_type == 0x9123683E)) {
274*33b1fccfSAndroid Build Coastguard Worker close(fd);
275*33b1fccfSAndroid Build Coastguard Worker unlink(dev);
276*33b1fccfSAndroid Build Coastguard Worker again = true;
277*33b1fccfSAndroid Build Coastguard Worker goto repeat;
278*33b1fccfSAndroid Build Coastguard Worker }
279*33b1fccfSAndroid Build Coastguard Worker #endif
280*33b1fccfSAndroid Build Coastguard Worker ret = ftruncate(fd, 0);
281*33b1fccfSAndroid Build Coastguard Worker if (ret) {
282*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to ftruncate(%s).", dev);
283*33b1fccfSAndroid Build Coastguard Worker close(fd);
284*33b1fccfSAndroid Build Coastguard Worker return -errno;
285*33b1fccfSAndroid Build Coastguard Worker }
286*33b1fccfSAndroid Build Coastguard Worker }
287*33b1fccfSAndroid Build Coastguard Worker sbi->devblksz = st.st_blksize;
288*33b1fccfSAndroid Build Coastguard Worker break;
289*33b1fccfSAndroid Build Coastguard Worker default:
290*33b1fccfSAndroid Build Coastguard Worker erofs_err("bad file type (%s, %o).", dev, st.st_mode);
291*33b1fccfSAndroid Build Coastguard Worker close(fd);
292*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
293*33b1fccfSAndroid Build Coastguard Worker }
294*33b1fccfSAndroid Build Coastguard Worker
295*33b1fccfSAndroid Build Coastguard Worker out:
296*33b1fccfSAndroid Build Coastguard Worker sbi->devname = strdup(dev);
297*33b1fccfSAndroid Build Coastguard Worker if (!sbi->devname) {
298*33b1fccfSAndroid Build Coastguard Worker close(fd);
299*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
300*33b1fccfSAndroid Build Coastguard Worker }
301*33b1fccfSAndroid Build Coastguard Worker sbi->bdev.fd = fd;
302*33b1fccfSAndroid Build Coastguard Worker erofs_info("successfully to open %s", dev);
303*33b1fccfSAndroid Build Coastguard Worker return 0;
304*33b1fccfSAndroid Build Coastguard Worker }
305*33b1fccfSAndroid Build Coastguard Worker
erofs_dev_close(struct erofs_sb_info * sbi)306*33b1fccfSAndroid Build Coastguard Worker void erofs_dev_close(struct erofs_sb_info *sbi)
307*33b1fccfSAndroid Build Coastguard Worker {
308*33b1fccfSAndroid Build Coastguard Worker if (!sbi->bdev.ops)
309*33b1fccfSAndroid Build Coastguard Worker close(sbi->bdev.fd);
310*33b1fccfSAndroid Build Coastguard Worker free(sbi->devname);
311*33b1fccfSAndroid Build Coastguard Worker sbi->devname = NULL;
312*33b1fccfSAndroid Build Coastguard Worker sbi->bdev.fd = -1;
313*33b1fccfSAndroid Build Coastguard Worker }
314*33b1fccfSAndroid Build Coastguard Worker
erofs_blob_closeall(struct erofs_sb_info * sbi)315*33b1fccfSAndroid Build Coastguard Worker void erofs_blob_closeall(struct erofs_sb_info *sbi)
316*33b1fccfSAndroid Build Coastguard Worker {
317*33b1fccfSAndroid Build Coastguard Worker unsigned int i;
318*33b1fccfSAndroid Build Coastguard Worker
319*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < sbi->nblobs; ++i)
320*33b1fccfSAndroid Build Coastguard Worker close(sbi->blobfd[i]);
321*33b1fccfSAndroid Build Coastguard Worker sbi->nblobs = 0;
322*33b1fccfSAndroid Build Coastguard Worker }
323*33b1fccfSAndroid Build Coastguard Worker
erofs_blob_open_ro(struct erofs_sb_info * sbi,const char * dev)324*33b1fccfSAndroid Build Coastguard Worker int erofs_blob_open_ro(struct erofs_sb_info *sbi, const char *dev)
325*33b1fccfSAndroid Build Coastguard Worker {
326*33b1fccfSAndroid Build Coastguard Worker int fd = open(dev, O_RDONLY | O_BINARY);
327*33b1fccfSAndroid Build Coastguard Worker
328*33b1fccfSAndroid Build Coastguard Worker if (fd < 0) {
329*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to open(%s).", dev);
330*33b1fccfSAndroid Build Coastguard Worker return -errno;
331*33b1fccfSAndroid Build Coastguard Worker }
332*33b1fccfSAndroid Build Coastguard Worker
333*33b1fccfSAndroid Build Coastguard Worker sbi->blobfd[sbi->nblobs] = fd;
334*33b1fccfSAndroid Build Coastguard Worker erofs_info("successfully to open blob%u %s", sbi->nblobs, dev);
335*33b1fccfSAndroid Build Coastguard Worker ++sbi->nblobs;
336*33b1fccfSAndroid Build Coastguard Worker return 0;
337*33b1fccfSAndroid Build Coastguard Worker }
338*33b1fccfSAndroid Build Coastguard Worker
erofs_dev_read(struct erofs_sb_info * sbi,int device_id,void * buf,u64 offset,size_t len)339*33b1fccfSAndroid Build Coastguard Worker ssize_t erofs_dev_read(struct erofs_sb_info *sbi, int device_id,
340*33b1fccfSAndroid Build Coastguard Worker void *buf, u64 offset, size_t len)
341*33b1fccfSAndroid Build Coastguard Worker {
342*33b1fccfSAndroid Build Coastguard Worker ssize_t read;
343*33b1fccfSAndroid Build Coastguard Worker
344*33b1fccfSAndroid Build Coastguard Worker if (device_id) {
345*33b1fccfSAndroid Build Coastguard Worker if (device_id >= sbi->nblobs) {
346*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid device id %d", device_id);
347*33b1fccfSAndroid Build Coastguard Worker return -EIO;
348*33b1fccfSAndroid Build Coastguard Worker }
349*33b1fccfSAndroid Build Coastguard Worker read = erofs_io_pread(&((struct erofs_vfile) {
350*33b1fccfSAndroid Build Coastguard Worker .fd = sbi->blobfd[device_id - 1],
351*33b1fccfSAndroid Build Coastguard Worker }), buf, offset, len);
352*33b1fccfSAndroid Build Coastguard Worker } else {
353*33b1fccfSAndroid Build Coastguard Worker read = erofs_io_pread(&sbi->bdev, buf, offset, len);
354*33b1fccfSAndroid Build Coastguard Worker }
355*33b1fccfSAndroid Build Coastguard Worker
356*33b1fccfSAndroid Build Coastguard Worker if (read < 0)
357*33b1fccfSAndroid Build Coastguard Worker return read;
358*33b1fccfSAndroid Build Coastguard Worker if (read < len) {
359*33b1fccfSAndroid Build Coastguard Worker erofs_info("reach EOF of device @ %llu, pading with zeroes",
360*33b1fccfSAndroid Build Coastguard Worker offset | 0ULL);
361*33b1fccfSAndroid Build Coastguard Worker memset(buf + read, 0, len - read);
362*33b1fccfSAndroid Build Coastguard Worker }
363*33b1fccfSAndroid Build Coastguard Worker return 0;
364*33b1fccfSAndroid Build Coastguard Worker }
365*33b1fccfSAndroid Build Coastguard Worker
__erofs_copy_file_range(int fd_in,u64 * off_in,int fd_out,u64 * off_out,size_t length)366*33b1fccfSAndroid Build Coastguard Worker static ssize_t __erofs_copy_file_range(int fd_in, u64 *off_in,
367*33b1fccfSAndroid Build Coastguard Worker int fd_out, u64 *off_out,
368*33b1fccfSAndroid Build Coastguard Worker size_t length)
369*33b1fccfSAndroid Build Coastguard Worker {
370*33b1fccfSAndroid Build Coastguard Worker size_t copied = 0;
371*33b1fccfSAndroid Build Coastguard Worker char buf[8192];
372*33b1fccfSAndroid Build Coastguard Worker
373*33b1fccfSAndroid Build Coastguard Worker /*
374*33b1fccfSAndroid Build Coastguard Worker * Main copying loop. The buffer size is arbitrary and is a
375*33b1fccfSAndroid Build Coastguard Worker * trade-off between stack size consumption, cache usage, and
376*33b1fccfSAndroid Build Coastguard Worker * amortization of system call overhead.
377*33b1fccfSAndroid Build Coastguard Worker */
378*33b1fccfSAndroid Build Coastguard Worker while (length > 0) {
379*33b1fccfSAndroid Build Coastguard Worker size_t to_read;
380*33b1fccfSAndroid Build Coastguard Worker ssize_t read_count;
381*33b1fccfSAndroid Build Coastguard Worker char *end, *p;
382*33b1fccfSAndroid Build Coastguard Worker
383*33b1fccfSAndroid Build Coastguard Worker to_read = min_t(size_t, length, sizeof(buf));
384*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PREAD64
385*33b1fccfSAndroid Build Coastguard Worker read_count = pread64(fd_in, buf, to_read, *off_in);
386*33b1fccfSAndroid Build Coastguard Worker #else
387*33b1fccfSAndroid Build Coastguard Worker read_count = pread(fd_in, buf, to_read, *off_in);
388*33b1fccfSAndroid Build Coastguard Worker #endif
389*33b1fccfSAndroid Build Coastguard Worker if (read_count == 0)
390*33b1fccfSAndroid Build Coastguard Worker /* End of file reached prematurely. */
391*33b1fccfSAndroid Build Coastguard Worker return copied;
392*33b1fccfSAndroid Build Coastguard Worker if (read_count < 0) {
393*33b1fccfSAndroid Build Coastguard Worker /* Report the number of bytes copied so far. */
394*33b1fccfSAndroid Build Coastguard Worker if (copied > 0)
395*33b1fccfSAndroid Build Coastguard Worker return copied;
396*33b1fccfSAndroid Build Coastguard Worker return -1;
397*33b1fccfSAndroid Build Coastguard Worker }
398*33b1fccfSAndroid Build Coastguard Worker *off_in += read_count;
399*33b1fccfSAndroid Build Coastguard Worker
400*33b1fccfSAndroid Build Coastguard Worker /* Write the buffer part which was read to the destination. */
401*33b1fccfSAndroid Build Coastguard Worker end = buf + read_count;
402*33b1fccfSAndroid Build Coastguard Worker for (p = buf; p < end; ) {
403*33b1fccfSAndroid Build Coastguard Worker ssize_t write_count;
404*33b1fccfSAndroid Build Coastguard Worker
405*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PWRITE64
406*33b1fccfSAndroid Build Coastguard Worker write_count = pwrite64(fd_out, p, end - p, *off_out);
407*33b1fccfSAndroid Build Coastguard Worker #else
408*33b1fccfSAndroid Build Coastguard Worker write_count = pwrite(fd_out, p, end - p, *off_out);
409*33b1fccfSAndroid Build Coastguard Worker #endif
410*33b1fccfSAndroid Build Coastguard Worker if (write_count < 0) {
411*33b1fccfSAndroid Build Coastguard Worker /*
412*33b1fccfSAndroid Build Coastguard Worker * Adjust the input read position to match what
413*33b1fccfSAndroid Build Coastguard Worker * we have written, so that the caller can pick
414*33b1fccfSAndroid Build Coastguard Worker * up after the error.
415*33b1fccfSAndroid Build Coastguard Worker */
416*33b1fccfSAndroid Build Coastguard Worker size_t written = p - buf;
417*33b1fccfSAndroid Build Coastguard Worker /*
418*33b1fccfSAndroid Build Coastguard Worker * NB: This needs to be signed so that we can
419*33b1fccfSAndroid Build Coastguard Worker * form the negative value below.
420*33b1fccfSAndroid Build Coastguard Worker */
421*33b1fccfSAndroid Build Coastguard Worker ssize_t overread = read_count - written;
422*33b1fccfSAndroid Build Coastguard Worker
423*33b1fccfSAndroid Build Coastguard Worker *off_in -= overread;
424*33b1fccfSAndroid Build Coastguard Worker /* Report the number of bytes copied so far. */
425*33b1fccfSAndroid Build Coastguard Worker if (copied + written > 0)
426*33b1fccfSAndroid Build Coastguard Worker return copied + written;
427*33b1fccfSAndroid Build Coastguard Worker return -1;
428*33b1fccfSAndroid Build Coastguard Worker }
429*33b1fccfSAndroid Build Coastguard Worker p += write_count;
430*33b1fccfSAndroid Build Coastguard Worker *off_out += write_count;
431*33b1fccfSAndroid Build Coastguard Worker } /* Write loop. */
432*33b1fccfSAndroid Build Coastguard Worker copied += read_count;
433*33b1fccfSAndroid Build Coastguard Worker length -= read_count;
434*33b1fccfSAndroid Build Coastguard Worker }
435*33b1fccfSAndroid Build Coastguard Worker return copied;
436*33b1fccfSAndroid Build Coastguard Worker }
437*33b1fccfSAndroid Build Coastguard Worker
erofs_copy_file_range(int fd_in,u64 * off_in,int fd_out,u64 * off_out,size_t length)438*33b1fccfSAndroid Build Coastguard Worker ssize_t erofs_copy_file_range(int fd_in, u64 *off_in, int fd_out, u64 *off_out,
439*33b1fccfSAndroid Build Coastguard Worker size_t length)
440*33b1fccfSAndroid Build Coastguard Worker {
441*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_COPY_FILE_RANGE
442*33b1fccfSAndroid Build Coastguard Worker off64_t off64_in = *off_in, off64_out = *off_out;
443*33b1fccfSAndroid Build Coastguard Worker ssize_t ret;
444*33b1fccfSAndroid Build Coastguard Worker
445*33b1fccfSAndroid Build Coastguard Worker ret = copy_file_range(fd_in, &off64_in, fd_out, &off64_out,
446*33b1fccfSAndroid Build Coastguard Worker length, 0);
447*33b1fccfSAndroid Build Coastguard Worker if (ret >= 0)
448*33b1fccfSAndroid Build Coastguard Worker goto out;
449*33b1fccfSAndroid Build Coastguard Worker if (errno != ENOSYS && errno != EXDEV) {
450*33b1fccfSAndroid Build Coastguard Worker ret = -errno;
451*33b1fccfSAndroid Build Coastguard Worker out:
452*33b1fccfSAndroid Build Coastguard Worker *off_in = off64_in;
453*33b1fccfSAndroid Build Coastguard Worker *off_out = off64_out;
454*33b1fccfSAndroid Build Coastguard Worker return ret;
455*33b1fccfSAndroid Build Coastguard Worker }
456*33b1fccfSAndroid Build Coastguard Worker #endif
457*33b1fccfSAndroid Build Coastguard Worker return __erofs_copy_file_range(fd_in, off_in, fd_out, off_out, length);
458*33b1fccfSAndroid Build Coastguard Worker }
459*33b1fccfSAndroid Build Coastguard Worker
erofs_io_read(struct erofs_vfile * vf,void * buf,size_t bytes)460*33b1fccfSAndroid Build Coastguard Worker ssize_t erofs_io_read(struct erofs_vfile *vf, void *buf, size_t bytes)
461*33b1fccfSAndroid Build Coastguard Worker {
462*33b1fccfSAndroid Build Coastguard Worker ssize_t i = 0;
463*33b1fccfSAndroid Build Coastguard Worker
464*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
465*33b1fccfSAndroid Build Coastguard Worker return vf->ops->read(vf, buf, bytes);
466*33b1fccfSAndroid Build Coastguard Worker
467*33b1fccfSAndroid Build Coastguard Worker while (bytes) {
468*33b1fccfSAndroid Build Coastguard Worker int len = bytes > INT_MAX ? INT_MAX : bytes;
469*33b1fccfSAndroid Build Coastguard Worker int ret;
470*33b1fccfSAndroid Build Coastguard Worker
471*33b1fccfSAndroid Build Coastguard Worker ret = read(vf->fd, buf + i, len);
472*33b1fccfSAndroid Build Coastguard Worker if (ret < 1) {
473*33b1fccfSAndroid Build Coastguard Worker if (ret == 0) {
474*33b1fccfSAndroid Build Coastguard Worker break;
475*33b1fccfSAndroid Build Coastguard Worker } else if (errno != EINTR) {
476*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read : %s",
477*33b1fccfSAndroid Build Coastguard Worker strerror(errno));
478*33b1fccfSAndroid Build Coastguard Worker return -errno;
479*33b1fccfSAndroid Build Coastguard Worker }
480*33b1fccfSAndroid Build Coastguard Worker }
481*33b1fccfSAndroid Build Coastguard Worker bytes -= ret;
482*33b1fccfSAndroid Build Coastguard Worker i += ret;
483*33b1fccfSAndroid Build Coastguard Worker }
484*33b1fccfSAndroid Build Coastguard Worker return i;
485*33b1fccfSAndroid Build Coastguard Worker }
486*33b1fccfSAndroid Build Coastguard Worker
487*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_SYS_SENDFILE_H
488*33b1fccfSAndroid Build Coastguard Worker #include <sys/sendfile.h>
489*33b1fccfSAndroid Build Coastguard Worker #endif
490*33b1fccfSAndroid Build Coastguard Worker
erofs_io_lseek(struct erofs_vfile * vf,u64 offset,int whence)491*33b1fccfSAndroid Build Coastguard Worker off_t erofs_io_lseek(struct erofs_vfile *vf, u64 offset, int whence)
492*33b1fccfSAndroid Build Coastguard Worker {
493*33b1fccfSAndroid Build Coastguard Worker if (vf->ops)
494*33b1fccfSAndroid Build Coastguard Worker return vf->ops->lseek(vf, offset, whence);
495*33b1fccfSAndroid Build Coastguard Worker
496*33b1fccfSAndroid Build Coastguard Worker return lseek(vf->fd, offset, whence);
497*33b1fccfSAndroid Build Coastguard Worker }
498*33b1fccfSAndroid Build Coastguard Worker
erofs_io_xcopy(struct erofs_vfile * vout,off_t pos,struct erofs_vfile * vin,unsigned int len,bool noseek)499*33b1fccfSAndroid Build Coastguard Worker int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos,
500*33b1fccfSAndroid Build Coastguard Worker struct erofs_vfile *vin, unsigned int len, bool noseek)
501*33b1fccfSAndroid Build Coastguard Worker {
502*33b1fccfSAndroid Build Coastguard Worker if (vout->ops)
503*33b1fccfSAndroid Build Coastguard Worker return vout->ops->xcopy(vout, pos, vin, len, noseek);
504*33b1fccfSAndroid Build Coastguard Worker
505*33b1fccfSAndroid Build Coastguard Worker if (len && !vin->ops) {
506*33b1fccfSAndroid Build Coastguard Worker off_t ret __maybe_unused;
507*33b1fccfSAndroid Build Coastguard Worker
508*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_COPY_FILE_RANGE
509*33b1fccfSAndroid Build Coastguard Worker ret = copy_file_range(vin->fd, NULL, vout->fd, &pos, len, 0);
510*33b1fccfSAndroid Build Coastguard Worker if (ret > 0)
511*33b1fccfSAndroid Build Coastguard Worker len -= ret;
512*33b1fccfSAndroid Build Coastguard Worker #endif
513*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_SYS_SENDFILE_H) && defined(HAVE_SENDFILE)
514*33b1fccfSAndroid Build Coastguard Worker if (len && !noseek) {
515*33b1fccfSAndroid Build Coastguard Worker ret = lseek(vout->fd, pos, SEEK_SET);
516*33b1fccfSAndroid Build Coastguard Worker if (ret == pos) {
517*33b1fccfSAndroid Build Coastguard Worker ret = sendfile(vout->fd, vin->fd, NULL, len);
518*33b1fccfSAndroid Build Coastguard Worker if (ret > 0) {
519*33b1fccfSAndroid Build Coastguard Worker pos += ret;
520*33b1fccfSAndroid Build Coastguard Worker len -= ret;
521*33b1fccfSAndroid Build Coastguard Worker }
522*33b1fccfSAndroid Build Coastguard Worker }
523*33b1fccfSAndroid Build Coastguard Worker }
524*33b1fccfSAndroid Build Coastguard Worker #endif
525*33b1fccfSAndroid Build Coastguard Worker }
526*33b1fccfSAndroid Build Coastguard Worker
527*33b1fccfSAndroid Build Coastguard Worker do {
528*33b1fccfSAndroid Build Coastguard Worker char buf[32768];
529*33b1fccfSAndroid Build Coastguard Worker int ret = min_t(unsigned int, len, sizeof(buf));
530*33b1fccfSAndroid Build Coastguard Worker
531*33b1fccfSAndroid Build Coastguard Worker ret = erofs_io_read(vin, buf, ret);
532*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
533*33b1fccfSAndroid Build Coastguard Worker return ret;
534*33b1fccfSAndroid Build Coastguard Worker if (ret > 0) {
535*33b1fccfSAndroid Build Coastguard Worker ret = erofs_io_pwrite(vout, buf, pos, ret);
536*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
537*33b1fccfSAndroid Build Coastguard Worker return ret;
538*33b1fccfSAndroid Build Coastguard Worker pos += ret;
539*33b1fccfSAndroid Build Coastguard Worker }
540*33b1fccfSAndroid Build Coastguard Worker len -= ret;
541*33b1fccfSAndroid Build Coastguard Worker } while (len);
542*33b1fccfSAndroid Build Coastguard Worker return 0;
543*33b1fccfSAndroid Build Coastguard Worker }
544