1 /*-
2  * Copyright (c) 2010
3  *	Thorsten Glaser <tg@mirbsd.org>
4  *
5  * Provided that these terms and disclaimer and all copyright notices
6  * are retained or reproduced in an accompanying document, permission
7  * is granted to deal in this work without restriction, including un-
8  * limited rights to use, publicly perform, distribute, sell, modify,
9  * merge, give away, or sublicence.
10  *
11  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12  * the utmost extent permitted by applicable law, neither express nor
13  * implied; without malicious intent or gross negligence. In no event
14  * may a licensor, author or contributor be held liable for indirect,
15  * direct, other damage, loss, or other issues arising in any way out
16  * of dealing in the work, even if advised of the possibility of such
17  * damage or existence of a defect, except proven that it results out
18  * of said person's immediate fault when using the work as intended.
19  *-
20  * support routine for lseek+read to make 2048-byte aligned I/O
21  */
22 
23 #include <errno.h>
24 #include <mbfun.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 __RCSID("$MirOS: src/lib/libmbfun/cdblockedread.c,v 1.2 2010/11/12 20:53:28 tg Exp $");
30 
31 /* returns len if ok, 0 if ok but lseek to ofs+len failed, -1 otherwise */
32 ssize_t
cdblockedread(int fd,void * dst,size_t len,off_t ofs)33 cdblockedread(int fd, void *dst, size_t len, off_t ofs)
34 {
35 	off_t begsec, nlong;
36 	size_t begsecofs, n;
37 	ssize_t res;
38 	char *buf;
39 
40 	begsec = ofs & ~2047;			/* start cdsector */
41 	nlong = (ofs + len + 2047) & ~2047;	/* end+1 cdsector */
42 	nlong -= begsec;			/* num. bytes to read */
43 	begsecofs = (size_t)(ofs & 2047);	/* start in sector */
44 	n = (size_t)nlong;
45 	if (nlong != (off_t)n) {
46 		errno = EINVAL;			/* truncation */
47 		return (-1);
48 	}
49 	if ((buf = malloc(n)) == NULL)
50 		return (-1);
51 	nlong = lseek(fd, begsec, SEEK_SET);
52 	if (nlong != begsec)
53 		goto err;
54 	if ((res = read(fd, buf, n)) == -1)
55 		goto err;
56 	if ((size_t)res != n) {
57 		/* short read; try again in case this is a short file */
58 		if (lseek(fd, ofs, SEEK_SET) == ofs) {
59 			if ((res = read(fd, dst, len)) == -1)
60 				/* hard error, pass on errno */
61 				goto err;
62 			if ((size_t)res == len) {
63 				/* success, clean up and out */
64 				free(buf);
65 				return ((ssize_t)len);
66 			}
67 			/* soft error, short read */
68 		} /* else, soft error, lseek failed */
69 		errno = EIO;			/* short read */
70 		goto err;
71 	}
72 	memcpy(dst, buf + begsecofs, len);
73 	free(buf);
74 	/* correctly position seek pointer */
75 	ofs += len;
76 	nlong = lseek(fd, ofs, SEEK_SET);
77 	return (nlong == ofs ? (ssize_t)len : 0);
78 
79  err:
80 	free(buf);
81 	return (-1);
82 }
83