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