]> git.saurik.com Git - redis.git/blob - src/rio.c
Add checksum computation to rio.c
[redis.git] / src / rio.c
1 /* rio.c is a simple stream-oriented I/O abstraction that provides an interface
2 * to write code that can consume/produce data using different concrete input
3 * and output devices. For instance the same rdb.c code using the rio abstraction
4 * can be used to read and write the RDB format using in-memory buffers or files.
5 *
6 * A rio object provides the following methods:
7 * read: read from stream.
8 * write: write to stream.
9 * tell: get the current offset.
10 *
11 * It is also possible to set a 'checksum' method that is used by rio.c in order
12 * to compute a checksum of the data written or read, or to query the rio object
13 * for the current checksum. */
14
15 #include "fmacros.h"
16 #include <string.h>
17 #include <stdio.h>
18 #include "rio.h"
19 #include "util.h"
20
21 /* Returns 1 or 0 for success/failure. */
22 static size_t rioBufferWrite(rio *r, const void *buf, size_t len) {
23 r->io.buffer.ptr = sdscatlen(r->io.buffer.ptr,(char*)buf,len);
24 r->io.buffer.pos += len;
25 return 1;
26 }
27
28 /* Returns 1 or 0 for success/failure. */
29 static size_t rioBufferRead(rio *r, void *buf, size_t len) {
30 if (sdslen(r->io.buffer.ptr)-r->io.buffer.pos < len)
31 return 0; /* not enough buffer to return len bytes. */
32 memcpy(buf,r->io.buffer.ptr+r->io.buffer.pos,len);
33 r->io.buffer.pos += len;
34 return 1;
35 }
36
37 /* Returns read/write position in buffer. */
38 static off_t rioBufferTell(rio *r) {
39 return r->io.buffer.pos;
40 }
41
42 /* Returns 1 or 0 for success/failure. */
43 static size_t rioFileWrite(rio *r, const void *buf, size_t len) {
44 return fwrite(buf,len,1,r->io.file.fp);
45 }
46
47 /* Returns 1 or 0 for success/failure. */
48 static size_t rioFileRead(rio *r, void *buf, size_t len) {
49 return fread(buf,len,1,r->io.file.fp);
50 }
51
52 /* Returns read/write position in file. */
53 static off_t rioFileTell(rio *r) {
54 return ftello(r->io.file.fp);
55 }
56
57 static const rio rioBufferIO = {
58 rioBufferRead,
59 rioBufferWrite,
60 rioBufferTell,
61 NULL, /* update_checksum */
62 0, /* current checksum */
63 { { NULL, 0 } } /* union for io-specific vars */
64 };
65
66 static const rio rioFileIO = {
67 rioFileRead,
68 rioFileWrite,
69 rioFileTell,
70 NULL, /* update_checksum */
71 0, /* current checksum */
72 { { NULL, 0 } } /* union for io-specific vars */
73 };
74
75 void rioInitWithFile(rio *r, FILE *fp) {
76 *r = rioFileIO;
77 r->io.file.fp = fp;
78 }
79
80 void rioInitWithBuffer(rio *r, sds s) {
81 *r = rioBufferIO;
82 r->io.buffer.ptr = s;
83 r->io.buffer.pos = 0;
84 }
85
86 /* This function can be installed both in memory and file streams when checksum
87 * computation is needed. */
88 void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len) {
89 r->checksum = crc64(r->checksum,buf,len);
90 }
91
92 /* ------------------------------ Higher level interface ---------------------------
93 * The following higher level functions use lower level rio.c functions to help
94 * generating the Redis protocol for the Append Only File. */
95
96 /* Write multi bulk count in the format: "*<count>\r\n". */
97 size_t rioWriteBulkCount(rio *r, char prefix, int count) {
98 char cbuf[128];
99 int clen;
100
101 cbuf[0] = prefix;
102 clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,count);
103 cbuf[clen++] = '\r';
104 cbuf[clen++] = '\n';
105 if (rioWrite(r,cbuf,clen) == 0) return 0;
106 return clen;
107 }
108
109 /* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". */
110 size_t rioWriteBulkString(rio *r, const char *buf, size_t len) {
111 size_t nwritten;
112
113 if ((nwritten = rioWriteBulkCount(r,'$',len)) == 0) return 0;
114 if (len > 0 && rioWrite(r,buf,len) == 0) return 0;
115 if (rioWrite(r,"\r\n",2) == 0) return 0;
116 return nwritten+len+2;
117 }
118
119 /* Write a long long value in format: "$<count>\r\n<payload>\r\n". */
120 size_t rioWriteBulkLongLong(rio *r, long long l) {
121 char lbuf[32];
122 unsigned int llen;
123
124 llen = ll2string(lbuf,sizeof(lbuf),l);
125 return rioWriteBulkString(r,lbuf,llen);
126 }
127
128 /* Write a double value in the format: "$<count>\r\n<payload>\r\n" */
129 size_t rioWriteBulkDouble(rio *r, double d) {
130 char dbuf[128];
131 unsigned int dlen;
132
133 dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d);
134 return rioWriteBulkString(r,dbuf,dlen);
135 }