1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20 #include "test.h"
21 
22 #define INIT_BUF_SIZE 4
23 #define EXPANSION_COEFFICIENT 2
24 
25 struct cookie
26 {
27     size_t pos;
28     size_t len;
29     size_t size;
30     char *buf;
31 };
32 
mread(void *f, char *buf, size_t len)33 ssize_t mread(void *f, char *buf, size_t len)
34 {
35     struct cookie *c = f;
36     if (c->pos > c->len) {
37         return 0;
38     } else if (c->pos + len > c->len) {
39         len = c->len - c->pos;
40     }
41 
42     memcpy(buf, c->buf + c->pos, len);
43     c->pos += len;
44     return len;
45 }
46 
mwrite(void *f, const char *buf, size_t len)47 ssize_t mwrite(void *f, const char *buf, size_t len)
48 {
49     struct cookie *c = f;
50     char *newBuf;
51     if (c->pos + len > c->size) {
52         while (c->pos + len > c->size) {
53             c->size *= EXPANSION_COEFFICIENT;
54         }
55         newBuf = malloc(c->size);
56         if (newBuf == NULL) {
57             return -1;
58         } else {
59             memcpy(newBuf, c->buf, c->len);
60             free(c->buf);
61             c->size = c->pos + len;
62             c->buf = newBuf;
63         }
64     }
65 
66     memcpy(c->buf + c->pos, buf, len);
67     c->pos += len;
68     if (c->pos > c->len) {
69         c->len = c->pos;
70     }
71     return len;
72 }
73 
mseek(void *f, off_t *off, int whence)74 int mseek(void *f, off_t *off, int whence)
75 {
76     struct cookie *c = f;
77     off_t newPos;
78     if (whence == SEEK_SET) {
79         newPos = *off;
80     } else if (whence == SEEK_CUR) {
81         newPos = *off + c->pos;
82     } else if (whence == SEEK_END) {
83         newPos = *off + c->len;
84     } else {
85         return -1;
86     }
87     if (newPos < 0) {
88         return -1;
89     }
90 
91     c->pos = newPos;
92     *off = newPos;
93 
94     return 0;
95 }
96 
mclose(void *f)97 int mclose(void *f)
98 {
99     struct cookie *c = f;
100     free(c->buf);
101     c->buf = NULL;
102     return 0;
103 }
104 
main(int argc, char *argv[])105 int main(int argc, char *argv[])
106 {
107     cookie_io_functions_t ioFunc = {.read = mread, .write = mwrite, .seek = mseek, .close = mclose};
108     FILE *file;
109     struct cookie myc;
110     size_t nread;
111     size_t memberSize = 1;
112     size_t memberNumbers = 2;
113     char buf[50];
114     myc.buf = malloc(INIT_BUF_SIZE);
115     if (myc.buf == NULL) {
116         t_error("fopencookie malloc failed\n");
117         return 1;
118     }
119     myc.pos = 0;
120     myc.len = 0;
121     myc.size = INIT_BUF_SIZE;
122 
123     file = fopencookie(&myc, "w+", ioFunc);
124     if (file == NULL) {
125         t_error("create fopencookie failed\n");
126         return 1;
127     }
128     if (fputs("fopencookie", file) == EOF) {
129         t_error("fopencookie fputs failed\n");
130         return 1;
131     }
132     if (fseek(file, 0, SEEK_SET) == -1) {
133         t_error("fopencookie fseek failed\n");
134         return 1;
135     }
136     nread = fread(buf, memberSize, memberNumbers, file);
137     if (nread == 0) {
138         if (ferror(file) != 0) {
139             t_error("fopencookie fread failed\n");
140             return 1;
141         }
142     }
143     fclose(file);
144     return 0;
145 }