1/*
2    FUSE: Filesystem in Userspace
3    Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4
5    This program can be distributed under the terms of the GNU LGPLv2.
6    See the file COPYING.LIB
7*/
8
9#include "config.h"
10#include "fuse_lowlevel.h"
11#include "fuse_lowlevel_compat.h"
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <assert.h>
17#include <errno.h>
18
19struct fuse_session {
20    struct fuse_session_ops op;
21
22    void *data;
23
24    volatile int exited;
25
26    struct fuse_chan *ch;
27};
28
29struct fuse_chan {
30    struct fuse_chan_ops op;
31
32    struct fuse_session *se;
33
34    int fd;
35
36    size_t bufsize;
37
38    void *data;
39};
40
41struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
42{
43    struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
44    if (se == NULL) {
45        fprintf(stderr, "fuse: failed to allocate session\n");
46        return NULL;
47    }
48
49    memset(se, 0, sizeof(*se));
50    se->op = *op;
51    se->data = data;
52
53    return se;
54}
55
56void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
57{
58    assert(se->ch == NULL);
59    assert(ch->se == NULL);
60    se->ch = ch;
61    ch->se = se;
62}
63
64void fuse_session_remove_chan(struct fuse_chan *ch)
65{
66    struct fuse_session *se = ch->se;
67    if (se) {
68        assert(se->ch == ch);
69        se->ch = NULL;
70        ch->se = NULL;
71    }
72}
73
74struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
75                                         struct fuse_chan *ch)
76{
77    assert(ch == NULL || ch == se->ch);
78    if (ch == NULL)
79        return se->ch;
80    else
81        return NULL;
82}
83
84void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
85                          struct fuse_chan *ch)
86{
87    se->op.process(se->data, buf, len, ch);
88}
89
90void fuse_session_destroy(struct fuse_session *se)
91{
92    if (se->op.destroy)
93        se->op.destroy(se->data);
94    if (se->ch != NULL)
95        fuse_chan_destroy(se->ch);
96    free(se);
97}
98
99void fuse_session_exit(struct fuse_session *se)
100{
101    if (se->op.exit)
102        se->op.exit(se->data, 1);
103    se->exited = 1;
104}
105
106void fuse_session_reset(struct fuse_session *se)
107{
108    if (se->op.exit)
109        se->op.exit(se->data, 0);
110    se->exited = 0;
111}
112
113int fuse_session_exited(struct fuse_session *se)
114{
115    if (se->op.exited)
116        return se->op.exited(se->data);
117    else
118        return se->exited;
119}
120
121static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
122                                size_t bufsize, void *data)
123{
124    struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
125    if (ch == NULL) {
126        fprintf(stderr, "fuse: failed to allocate channel\n");
127        return NULL;
128    }
129
130    memset(ch, 0, sizeof(*ch));
131    ch->op = *op;
132    ch->fd = fd;
133    ch->bufsize = bufsize;
134    ch->data = data;
135
136    return ch;
137}
138
139struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
140                                size_t bufsize, void *data)
141{
142    return fuse_chan_new_common(op, fd, bufsize, data);
143}
144
145int fuse_chan_fd(struct fuse_chan *ch)
146{
147    return ch->fd;
148}
149
150size_t fuse_chan_bufsize(struct fuse_chan *ch)
151{
152    return ch->bufsize;
153}
154
155void *fuse_chan_data(struct fuse_chan *ch)
156{
157    return ch->data;
158}
159
160struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
161{
162    return ch->se;
163}
164
165int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
166{
167    struct fuse_chan *ch = *chp;
168    return ch->op.receive(chp, buf, size);
169}
170
171int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
172{
173    return ch->op.send(ch, iov, count);
174}
175
176void fuse_chan_destroy(struct fuse_chan *ch)
177{
178    fuse_session_remove_chan(ch);
179    if (ch->op.destroy)
180        ch->op.destroy(ch);
181    free(ch);
182}
183
184