xref: /aosp_15_r20/external/erofs-utils/lib/io.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
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