1 /*
2  * Copyright 2018 Jonathan Dieter <jdieter@gmail.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright notice,
8  *     this list of conditions and the following disclaimer.
9  *
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <zck.h>
34 
35 #include "zck_private.h"
36 
read_data(zckCtx * zck,char * data,size_t length)37 ssize_t read_data(zckCtx *zck, char *data, size_t length) {
38     VALIDATE_READ_INT(zck);
39 
40     if(length == 0)
41         return 0;
42     if(data == NULL) {
43         set_error(zck, "Unable to read to NULL data pointer");
44         return -1;
45     }
46     ssize_t read_bytes = read(zck->fd, data, length);
47     if(read_bytes == -1) {
48         set_error(zck, "Error reading data: %s", strerror(errno));
49         return -1;
50     }
51     return read_bytes;
52 }
53 
write_data(zckCtx * zck,int fd,const char * data,size_t length)54 int write_data(zckCtx *zck, int fd, const char *data, size_t length) {
55     VALIDATE_INT(zck);
56 
57     if(length == 0)
58         return true;
59     if(data == NULL) {
60         set_error(zck, "Unable to write from NULL data pointer");
61         return false;
62     }
63     ssize_t write_bytes = write(fd, data, length);
64     if(write_bytes == -1) {
65         set_fatal_error(zck, "Error writing data: %s", strerror(errno));
66         return false;
67     } else if(write_bytes < length) {
68         // According to man page, if write is less than full amount, we should try again
69         length -= write_bytes;
70         write_bytes = write(fd, data+write_bytes, length);
71         if(write_bytes == -1) {
72             set_fatal_error(zck, "Error writing data: %s", strerror(errno));
73             return false;
74         } else if(write_bytes < length) {
75             set_fatal_error(zck, "Short write (after two attempts)");
76             return false;
77         }
78     }
79     return true;
80 }
81 
seek_data(zckCtx * zck,off_t offset,int whence)82 int seek_data(zckCtx *zck, off_t offset, int whence) {
83     VALIDATE_INT(zck);
84 
85     if(lseek(zck->fd, offset, whence) == -1) {
86         char *wh_str = NULL;
87 
88         if(whence == SEEK_CUR) {
89             wh_str = "from current position";
90         } else if(whence == SEEK_END) {
91             wh_str = "from end of file";
92         } else if(whence == SEEK_SET) {
93             wh_str = "from beginning of file";
94         } else {
95             wh_str = "using unknown measurement";
96         }
97         set_error(zck, "Unable to seek to %lu %s: %s", offset, wh_str,
98                   strerror(errno));
99         return false;
100     }
101     return true;
102 }
103 
tell_data(zckCtx * zck)104 ssize_t tell_data(zckCtx *zck) {
105     ssize_t loc = lseek(zck->fd, 0, SEEK_CUR);
106     return loc;
107 }
108 
chunks_from_temp(zckCtx * zck)109 int chunks_from_temp(zckCtx *zck) {
110     int read_count;
111 
112     if(lseek(zck->temp_fd, 0, SEEK_SET) == -1)
113         return false;
114 
115     char *data = zmalloc(BUF_SIZE);
116 
117     while((read_count = read(zck->temp_fd, data, BUF_SIZE)) > 0) {
118         if(read_count == -1 || !write_data(zck, zck->fd, data, read_count)) {
119             free(data);
120             return false;
121         }
122     }
123     free(data);
124     return true;
125 }
126