Tizen 2.1 base
[framework/base/fuse.git] / example / fioc.c
1 /*
2   FUSE fioc: FUSE ioctl example
3   Copyright (C) 2008       SUSE Linux Products GmbH
4   Copyright (C) 2008       Tejun Heo <teheo@suse.de>
5
6   This program can be distributed under the terms of the GNU GPL.
7   See the file COPYING.
8
9   gcc -Wall fioc.c `pkg-config fuse --cflags --libs` -o fioc
10 */
11
12 #define FUSE_USE_VERSION 26
13
14 #include <fuse.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <time.h>
20 #include <errno.h>
21
22 #include "fioc.h"
23
24 #define FIOC_NAME       "fioc"
25
26 enum {
27         FIOC_NONE,
28         FIOC_ROOT,
29         FIOC_FILE,
30 };
31
32 static void *fioc_buf;
33 static size_t fioc_size;
34
35 static int fioc_resize(size_t new_size)
36 {
37         void *new_buf;
38
39         if (new_size == fioc_size)
40                 return 0;
41
42         new_buf = realloc(fioc_buf, new_size);
43         if (!new_buf && new_size)
44                 return -ENOMEM;
45
46         if (new_size > fioc_size)
47                 memset(new_buf + fioc_size, 0, new_size - fioc_size);
48
49         fioc_buf = new_buf;
50         fioc_size = new_size;
51
52         return 0;
53 }
54
55 static int fioc_expand(size_t new_size)
56 {
57         if (new_size > fioc_size)
58                 return fioc_resize(new_size);
59         return 0;
60 }
61
62 static int fioc_file_type(const char *path)
63 {
64         if (strcmp(path, "/") == 0)
65                 return FIOC_ROOT;
66         if (strcmp(path, "/" FIOC_NAME) == 0)
67                 return FIOC_FILE;
68         return FIOC_NONE;
69 }
70
71 static int fioc_getattr(const char *path, struct stat *stbuf)
72 {
73         stbuf->st_uid = getuid();
74         stbuf->st_gid = getgid();
75         stbuf->st_atime = stbuf->st_mtime = time(NULL);
76
77         switch (fioc_file_type(path)) {
78         case FIOC_ROOT:
79                 stbuf->st_mode = S_IFDIR | 0755;
80                 stbuf->st_nlink = 2;
81                 break;
82         case FIOC_FILE:
83                 stbuf->st_mode = S_IFREG | 0644;
84                 stbuf->st_nlink = 1;
85                 stbuf->st_size = fioc_size;
86                 break;
87         case FIOC_NONE:
88                 return -ENOENT;
89         }
90
91         return 0;
92 }
93
94 static int fioc_open(const char *path, struct fuse_file_info *fi)
95 {
96         (void) fi;
97
98         if (fioc_file_type(path) != FIOC_NONE)
99                 return 0;
100         return -ENOENT;
101 }
102
103 static int fioc_do_read(char *buf, size_t size, off_t offset)
104 {
105         if (offset >= fioc_size)
106                 return 0;
107
108         if (size > fioc_size - offset)
109                 size = fioc_size - offset;
110
111         memcpy(buf, fioc_buf + offset, size);
112
113         return size;
114 }
115
116 static int fioc_read(const char *path, char *buf, size_t size,
117                      off_t offset, struct fuse_file_info *fi)
118 {
119         (void) fi;
120
121         if (fioc_file_type(path) != FIOC_FILE)
122                 return -EINVAL;
123
124         return fioc_do_read(buf, size, offset);
125 }
126
127 static int fioc_do_write(const char *buf, size_t size, off_t offset)
128 {
129         if (fioc_expand(offset + size))
130                 return -ENOMEM;
131
132         memcpy(fioc_buf + offset, buf, size);
133
134         return size;
135 }
136
137 static int fioc_write(const char *path, const char *buf, size_t size,
138                       off_t offset, struct fuse_file_info *fi)
139 {
140         (void) fi;
141
142         if (fioc_file_type(path) != FIOC_FILE)
143                 return -EINVAL;
144
145         return fioc_do_write(buf, size, offset);
146 }
147
148 static int fioc_truncate(const char *path, off_t size)
149 {
150         if (fioc_file_type(path) != FIOC_FILE)
151                 return -EINVAL;
152
153         return fioc_resize(size);
154 }
155
156 static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
157                         off_t offset, struct fuse_file_info *fi)
158 {
159         (void) fi;
160         (void) offset;
161
162         if (fioc_file_type(path) != FIOC_ROOT)
163                 return -ENOENT;
164
165         filler(buf, ".", NULL, 0);
166         filler(buf, "..", NULL, 0);
167         filler(buf, FIOC_NAME, NULL, 0);
168
169         return 0;
170 }
171
172 static int fioc_ioctl(const char *path, int cmd, void *arg,
173                       struct fuse_file_info *fi, unsigned int flags, void *data)
174 {
175         (void) arg;
176         (void) fi;
177         (void) flags;
178
179         if (fioc_file_type(path) != FIOC_FILE)
180                 return -EINVAL;
181
182         if (flags & FUSE_IOCTL_COMPAT)
183                 return -ENOSYS;
184
185         switch (cmd) {
186         case FIOC_GET_SIZE:
187                 *(size_t *)data = fioc_size;
188                 return 0;
189
190         case FIOC_SET_SIZE:
191                 fioc_resize(*(size_t *)data);
192                 return 0;
193         }
194
195         return -EINVAL;
196 }
197
198 static struct fuse_operations fioc_oper = {
199         .getattr        = fioc_getattr,
200         .readdir        = fioc_readdir,
201         .truncate       = fioc_truncate,
202         .open           = fioc_open,
203         .read           = fioc_read,
204         .write          = fioc_write,
205         .ioctl          = fioc_ioctl,
206 };
207
208 int main(int argc, char *argv[])
209 {
210         return fuse_main(argc, argv, &fioc_oper, NULL);
211 }