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
25struct cookie
26{
27    size_t pos;
28    size_t len;
29    size_t size;
30    char *buf;
31};
32
33ssize_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
47ssize_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
74int 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
97int mclose(void *f)
98{
99    struct cookie *c = f;
100    free(c->buf);
101    c->buf = NULL;
102    return 0;
103}
104
105int 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}