Add file plugin.
[nbdkit/ericb.git] / plugins / file / file.c
blob34121e18c62dab23d7f3ffb3b44b45ec8114c841
1 /* nbdkit
2 * Copyright (C) 2013 Red Hat Inc.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Red Hat nor the names of its contributors may be
17 * used to endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include <config.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
44 #include <nbdkit-plugin.h>
46 static char *filename = NULL;
48 static void
49 file_unload (void)
51 free (filename);
54 /* Called for each key=value passed on the command line. This plugin
55 * only accepts file=<filename>, which is required.
57 static int
58 file_config (const char *key, const char *value)
60 if (strcmp (key, "file") == 0) {
61 /* See FILENAMES AND PATHS in nbdkit-plugin(3). */
62 filename = nbdkit_absolute_path (value);
63 if (!filename)
64 return -1;
66 else {
67 nbdkit_error ("unknown parameter '%s'", key);
68 return -1;
71 return 0;
74 /* Check the user did pass a file=<FILENAME> parameter. */
75 static int
76 file_config_complete (void)
78 if (filename == NULL) {
79 nbdkit_error ("you must supply the file=<FILENAME> parameter after the plugin name on the command line");
80 return -1;
83 return 0;
86 #define file_config_help \
87 "file=<FILENAME> (required) The filename to serve."
89 /* The per-connection handle. */
90 struct handle {
91 int fd;
94 /* Create the per-connection handle. */
95 static void *
96 file_open (int readonly)
98 struct handle *h;
99 int flags;
101 h = malloc (sizeof *h);
102 if (h == NULL) {
103 nbdkit_error ("malloc: %m");
104 return NULL;
107 flags = O_CLOEXEC|O_NOCTTY;
108 if (readonly)
109 flags |= O_RDONLY;
110 else
111 flags |= O_RDWR;
113 h->fd = open (filename, flags);
114 if (h->fd == -1) {
115 nbdkit_error ("open: %s: %m", filename);
116 free (h);
117 return NULL;
120 return h;
123 /* Free up the per-connection handle. */
124 static void
125 file_close (void *handle)
127 struct handle *h = handle;
129 close (h->fd);
130 free (h);
133 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
135 /* Get the file size. */
136 static int64_t
137 file_get_size (void *handle)
139 struct handle *h = handle;
140 struct stat statbuf;
142 if (fstat (h->fd, &statbuf) == -1) {
143 nbdkit_error ("stat: %m");
144 return -1;
147 return statbuf.st_size;
150 /* Read data from the file. */
151 static int
152 file_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
154 struct handle *h = handle;
156 while (count > 0) {
157 ssize_t r = pread (h->fd, buf, count, offset);
158 if (r == -1) {
159 nbdkit_error ("pread: %m");
160 return -1;
162 if (r == 0) {
163 nbdkit_error ("pread: unexpected end of file");
164 return -1;
166 buf += r;
167 count -= r;
168 offset += r;
171 return 0;
174 /* Write data to the file. */
175 static int
176 file_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
178 struct handle *h = handle;
180 while (count > 0) {
181 ssize_t r = pwrite (h->fd, buf, count, offset);
182 if (r == -1) {
183 nbdkit_error ("pwrite: %m");
184 return -1;
186 buf += r;
187 count -= r;
188 offset += r;
191 return 0;
194 /* Flush the file to disk. */
195 static int
196 file_flush (void *handle)
198 struct handle *h = handle;
200 if (fdatasync (h->fd) == -1) {
201 nbdkit_error ("fdatasync: %m");
202 return -1;
205 return 0;
208 static struct nbdkit_plugin plugin = {
209 .name = "file",
210 .longname = "nbdkit file plugin",
211 .version = PACKAGE_VERSION,
212 .unload = file_unload,
213 .config = file_config,
214 .config_complete = file_config_complete,
215 .config_help = file_config_help,
216 .open = file_open,
217 .close = file_close,
218 .get_size = file_get_size,
219 .pread = file_pread,
220 .pwrite = file_pwrite,
221 .flush = file_flush,
224 NBDKIT_REGISTER_PLUGIN(plugin)