library name fixups
[libmvfs.git] / libmvfs / mixp_ops.c
blobb3dc913d18c88ffb91172f0854bbd618fa332d4d
1 /*
2 libmvfs - metux Virtual Filesystem Library
4 Filesystem driver: 9P via libmixp
6 Copyright (C) 2008 Enrico Weigelt, metux IT service <weigelt@metux.de>
7 This code is published under the terms of the GNU Public License 2.0
8 */
10 // #define _DEBUG
12 #include "mvfs-internal.h"
14 #define _LARGEFILE64_SOURCE
16 #include <sys/types.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <malloc.h>
24 #include <mvfs/mvfs.h>
25 #include <mvfs/default_ops.h>
26 #include <mvfs/mixpfs.h>
27 #include <mvfs/_utils.h>
29 #include <9p-mixp/mixp.h>
31 #define MIXP_FS_CLIENT(fs) ((MIXP_CLIENT*)(fs->priv.ptr))
33 #define FS_MAGIC "metux/mixp-fs-1"
35 static inline char* SSTRDUP(const char* str)
37 if (str==NULL)
38 return strdup("");
39 else
40 return strdup(str);
43 static off64_t mvfs_mixpfs_fileops_seek (MVFS_FILE* file, off64_t offset, int whence);
44 static ssize_t mvfs_mixpfs_fileops_pread (MVFS_FILE* file, void* buf, size_t count, off64_t offset);
45 static ssize_t mvfs_mixpfs_fileops_pwrite (MVFS_FILE* file, const void* buf, size_t count, off64_t offset);
46 static ssize_t mvfs_mixpfs_fileops_read (MVFS_FILE* file, void* buf, size_t count);
47 static ssize_t mvfs_mixpfs_fileops_write (MVFS_FILE* file, const void* buf, size_t count);
48 static int mvfs_mixpfs_fileops_close (MVFS_FILE* file);
49 static int mvfs_mixpfs_fileops_free (MVFS_FILE* file);
50 static int mvfs_mixpfs_fileops_eof (MVFS_FILE* file);
51 static MVFS_STAT* mvfs_mixpfs_fileops_stat (MVFS_FILE* file);
52 static MVFS_FILE* mvfs_mixpfs_fileops_lookup (MVFS_FILE* file, const char* name);
53 static MVFS_STAT* mvfs_mixpfs_fileops_scan (MVFS_FILE* file);
54 static int mvfs_mixpfs_fileops_reset (MVFS_FILE* file);
56 static MVFS_FILE_OPS mixpfs_fileops =
58 .seek = mvfs_mixpfs_fileops_seek,
59 .read = mvfs_mixpfs_fileops_read,
60 .write = mvfs_mixpfs_fileops_write,
61 .pread = mvfs_mixpfs_fileops_pread,
62 .pwrite = mvfs_mixpfs_fileops_pwrite,
63 .close = mvfs_mixpfs_fileops_close,
64 .free = mvfs_mixpfs_fileops_free,
65 .eof = mvfs_mixpfs_fileops_eof,
66 .lookup = mvfs_mixpfs_fileops_lookup,
67 .scan = mvfs_mixpfs_fileops_scan,
68 .reset = mvfs_mixpfs_fileops_reset,
69 .stat = mvfs_mixpfs_fileops_stat
72 static MVFS_STAT* mvfs_mixpfs_fsops_stat (MVFS_FILESYSTEM* fs, const char* name);
73 static MVFS_FILE* mvfs_mixpfs_fsops_open (MVFS_FILESYSTEM* fs, const char* name, mode_t mode);
74 static int mvfs_mixpfs_fsops_unlink (MVFS_FILESYSTEM* fs, const char* name);
76 static MVFS_FILESYSTEM_OPS mixpfs_fsops =
78 .openfile = mvfs_mixpfs_fsops_open,
79 .unlink = mvfs_mixpfs_fsops_unlink,
80 .stat = mvfs_mixpfs_fsops_stat
83 typedef struct _mixp_dirent MIXP_DIRENT;
84 struct _mixp_dirent
86 MIXP_STAT* stat;
87 MIXP_DIRENT* next;
90 typedef struct
92 MIXP_CFID* cfid;
93 char* pathname;
94 int eof;
95 off64_t pos;
96 MIXP_DIRENT* dirents;
97 MIXP_DIRENT* dirptr;
98 } MIXP_FILE_PRIV;
100 #ifdef _MVFS_SANITY_CHECKS
102 #define __FILEOPS_HEAD(err); \
103 if (file==NULL) \
105 ERRMSG("NULL file handle"); \
106 return err; \
108 MIXP_FILE_PRIV* priv = (file->priv.ptr); \
109 if (priv == NULL) \
111 ERRMSG("corrupt file handle"); \
112 return err; \
115 #else
117 #define __FILEOPS_HEAD(err); \
118 MIXP_FILE_PRIV* priv = (file->priv.ptr); \
120 #endif
122 static int __mixp_flushdir(MVFS_FILE* file)
124 __FILEOPS_HEAD(-EFAULT);
125 MIXP_DIRENT* walk;
126 for (walk=priv->dirents; walk; walk=priv->dirents)
128 mixp_stat_free(walk->stat);
129 free(walk);
131 priv->dirents = priv->dirptr = NULL;
132 return 0;
135 static int __mixp_readdir(MVFS_FILE* file)
137 __FILEOPS_HEAD(-EFAULT);
139 // directory already loaded ?
140 if (priv->dirents != NULL)
141 return 0;
143 MIXP_CFID* fid;
144 char* buf;
145 int lflag;
146 int dflag;
147 int i;
150 MIXP_STAT* stat = mixp_stat(MIXP_FS_CLIENT(file->fs), priv->pathname);
151 if (stat==NULL)
153 DEBUGMSG("couldnt stat dir: \"%s\"", priv->pathname);
154 return -ENOENT;
156 if ((stat->mode & P9_DMDIR) == 0)
158 DEBUGMSG("file \"%s\" is not an directory", priv->pathname);
159 mixp_stat_free(stat);
160 return -1;
162 mixp_stat_free(stat);
165 fid = mixp_open(MIXP_FS_CLIENT(file->fs), priv->pathname, P9_OREAD);
166 if (fid == NULL)
168 DEBUGMSG("couldnt open file \"%s\"", priv->pathname);
169 return -ENOENT;
173 int count;
174 MIXP_STAT* newstat;
175 MIXP_MESSAGE m;
176 MIXP_DIRENT* entries = NULL;
177 MIXP_DIRENT* walk = NULL;
178 buf = calloc(1,fid->iounit);
179 while ((count = mixp_read(fid, buf, fid->iounit))>0)
181 m = mixp_message(buf, count, MsgUnpack);
182 while (m.pos < m.end)
184 newstat = calloc(1,sizeof(MIXP_STAT));
185 mixp_pstat(&m, newstat);
186 if (entries == NULL)
188 entries = walk = (MIXP_DIRENT*)calloc(1,sizeof(MIXP_DIRENT));
190 else
192 walk->next = (MIXP_DIRENT*)calloc(1,sizeof(MIXP_DIRENT));
193 walk = walk->next;
195 walk->stat = newstat;
196 newstat = NULL;
199 priv->dirents = priv->dirptr = entries;
203 off64_t mvfs_mixpfs_fileops_seek (MVFS_FILE* file, off64_t offset, int whence)
205 __FILEOPS_HEAD((off64_t)-1);
207 // FIXME: should check if the position is valid
208 switch (whence)
210 case SEEK_SET: priv->pos = offset; break;
211 case SEEK_CUR: priv->pos += offset; break;
212 case SEEK_END:
213 DEBUGMSG("WARN: 9p/mixp: SEEK_END not implemented yet");
214 file->errcode = EINVAL;
215 return (off64_t)-1;
216 default:
217 DEBUGMSG("WARN: mixp::seek() unknown whence %d", whence);
218 file->errcode = EINVAL;
219 return (off64_t)-1;
223 ssize_t mvfs_mixpfs_fileops_pread (MVFS_FILE* file, void* buf, size_t count, off64_t offset)
225 __FILEOPS_HEAD((ssize_t)-1);
227 memset(buf, 0, count);
228 ssize_t ret = mixp_pread(priv->cfid, buf, count, offset);
229 if (ret<1) // 0 and -1 signal EOF ;-o
231 priv->eof=1;
232 return 0;
235 priv->pos+=ret;
236 return ret;
239 ssize_t mvfs_mixpfs_fileops_read (MVFS_FILE* file, void* buf, size_t count)
241 __FILEOPS_HEAD((ssize_t)-1);
242 memset(buf, 0, count);
243 ssize_t ret = mixp_read(priv->cfid, buf, count);
244 if (ret<1) // 0 and -1 signal EOF ;-o
246 priv->eof=1;
247 return 0;
250 priv->pos+=ret;
251 return ret;
254 ssize_t mvfs_mixpfs_fileops_write (MVFS_FILE* file, const void* buf, size_t count)
256 __FILEOPS_HEAD((ssize_t)-1);
257 ssize_t s = mixp_write(priv->cfid, buf, count);
258 priv->pos+=s;
259 return s;
262 ssize_t mvfs_mixpfs_fileops_pwrite (MVFS_FILE* file, const void* buf, size_t count, off64_t offset)
264 __FILEOPS_HEAD(-1);
265 ssize_t s = mixp_pwrite(priv->cfid, buf, count, offset);
266 priv->pos+=s;
267 return s;
270 static inline const char* __mvfs_flag2str(MVFS_FILE_FLAG f)
272 switch (f)
274 case NONBLOCK: return "NONBLOCK";
275 case READ_TIMEOUT: return "READ_TIMEOUT";
276 case WRITE_TIMEOUT: return "WRITE_TIMEOUT";
277 case READ_AHEAD: return "READ_AHEAD";
278 case WRITE_ASYNC: return "WRITE_ASYNNC";
279 default: return "UNKNOWN";
283 int mvfs_mixpfs_fileops_setflag (MVFS_FILE* file, MVFS_FILE_FLAG flag, long value)
285 __FILEOPS_HEAD(-1);
286 DEBUGMSG("%s not supported", __mvfs_flag2str(flag));
287 file->errcode = EINVAL;
288 return -1;
291 int mvfs_mixpfs_fileops_getflag (MVFS_FILE* file, MVFS_FILE_FLAG flag, long* value)
293 __FILEOPS_HEAD(-1);
294 DEBUGMSG("%s not supported", __mvfs_flag2str(flag));
295 file->errcode = EINVAL;
296 return -1;
299 static inline MVFS_STAT* _convert_stat(MIXP_STAT* st)
301 if (st == NULL)
303 ERRMSG("NULL stat");
304 return NULL;
307 MVFS_STAT* stat_mvfs = (MVFS_STAT*)calloc(1,sizeof(MVFS_STAT));
309 stat_mvfs->name = SSTRDUP(st->name);
310 stat_mvfs->uid = SSTRDUP(st->uid);
311 stat_mvfs->gid = SSTRDUP(st->gid);
313 stat_mvfs->mode = 0;
314 stat_mvfs->size = st->length;
315 stat_mvfs->mtime = st->mtime;
316 stat_mvfs->atime = st->atime;
317 stat_mvfs->ctime = st->mtime;
319 int mode = st->mode;
321 if (mode & P9_DMDIR)
322 stat_mvfs->mode |= S_IFDIR;
323 else if (mode & P9_DMSYMLINK)
324 stat_mvfs->mode |= S_IFLNK;
325 else if (mode & P9_DMDEVICE)
326 stat_mvfs->mode |= S_IFCHR;
327 else if (mode & P9_DMNAMEDPIPE)
328 stat_mvfs->mode |= S_IFIFO;
329 else if (mode & P9_DMSOCKET)
330 stat_mvfs->mode |= S_IFSOCK;
331 else
332 stat_mvfs->mode |= S_IFREG;
334 if (mode & P9_DMSETUID)
335 stat_mvfs->mode |= S_ISUID;
336 if (mode & P9_DMSETGID)
337 stat_mvfs->mode |= S_ISGID;
338 if (mode & S_IRUSR)
339 stat_mvfs->mode |= S_IRUSR;
340 if (mode & S_IWUSR)
341 stat_mvfs->mode |= S_IWUSR;
342 if (mode & S_IXUSR)
343 stat_mvfs->mode |= S_IXUSR;
344 if (mode & S_IRGRP)
345 stat_mvfs->mode |= S_IRGRP;
346 if (mode & S_IWGRP)
347 stat_mvfs->mode |= S_IWGRP;
348 if (mode & S_IXGRP)
349 stat_mvfs->mode |= S_IXGRP;
350 if (mode & S_IROTH)
351 stat_mvfs->mode |= S_IROTH;
352 if (mode & S_IWOTH)
353 stat_mvfs->mode |= S_IWOTH;
354 if (mode & S_IXOTH)
355 stat_mvfs->mode |= S_IXOTH;
357 return stat_mvfs;
360 MVFS_STAT* mvfs_mixpfs_fileops_stat(MVFS_FILE* file)
362 __FILEOPS_HEAD(NULL);
363 MIXP_STAT* mst = mixp_stat(MIXP_FS_CLIENT(file->fs), priv->pathname);
364 MVFS_STAT* st = _convert_stat(mst);
365 if (st == NULL)
366 file->errcode = EINVAL;
367 else
368 file->errcode = 0;
369 mixp_stat_free(mst);
370 return st;
373 // FIXME: handle the various file modes !!!
374 MVFS_FILE* mvfs_mixpfs_fsops_open(MVFS_FILESYSTEM* fs, const char* name, mode_t mode)
376 int m = 0;
377 if (mode & O_RDWR)
378 m = P9_ORDWR;
379 else if (mode & O_WRONLY)
380 m = P9_OWRITE;
381 else
382 m = P9_OREAD;
384 MIXP_CFID* fid = mixp_open(MIXP_FS_CLIENT(fs), name, m);
385 if (fid == NULL)
387 DEBUGMSG("couldnt open file: \"%s\"", name);
388 fs->errcode = ENOENT;
389 return NULL;
392 MVFS_FILE* file = mvfs_file_alloc(fs,mixpfs_fileops);
393 MIXP_FILE_PRIV* priv = calloc(1,sizeof(MIXP_FILE_PRIV));
394 file->priv.ptr = priv;
396 priv->cfid = fid;
397 priv->pos = 0;
398 priv->pathname = SSTRDUP(name);
400 return file;
403 MVFS_STAT* mvfs_mixpfs_fsops_stat(MVFS_FILESYSTEM* fs, const char* name)
405 if (fs==NULL)
407 ERRMSG("NULL fs passed !");
408 return NULL;
411 MIXP_STAT* mst = mixp_stat(MIXP_FS_CLIENT(fs), name);
412 MVFS_STAT* st = _convert_stat(mst);
413 mixp_stat_free(mst);
414 if (st == NULL)
416 ERRMSG("NULL stat");
417 fs->errcode = EINVAL;
418 return NULL;
421 return st;
424 int mvfs_mixpfs_fsops_unlink(MVFS_FILESYSTEM* fs, const char* name)
426 DEBUGMSG("FIXME: DUMMY");
427 fs->errcode = EPERM;
428 return errno;
431 MVFS_FILESYSTEM* mvfs_mixpfs_create_args(MVFS_ARGS* args)
433 const char* url = mvfs_args_get(args,"url");
434 const char* path= mvfs_args_get(args,"path");
436 if (path && strlen(path) && strcmp("/",path))
438 ERRMSG("chroot not supported yet path=\"%s\"", path);
439 return NULL;
442 MIXP_SERVER_ADDRESS* addr = mixp_srv_addr_parse(url);
443 if (addr==NULL)
445 ERRMSG("could not parse address \"%s\"", url);
446 return NULL;
449 MIXP_CLIENT* client = mixp_mount_addr(addr);
450 if (client == NULL)
452 ERRMSG("could not mount service @ \"%s\"", url);
453 return NULL;
456 MVFS_FILESYSTEM* fs = mvfs_fs_alloc(mixpfs_fsops,FS_MAGIC);
457 fs->priv.ptr=client;
459 return fs;
462 int mvfs_mixpfs_fileops_close(MVFS_FILE* file)
464 __FILEOPS_HEAD(-1);
465 if (priv->cfid)
466 mixp_close(priv->cfid);
467 priv->cfid=NULL;
468 priv->eof=0;
469 priv->pos=-1;
470 if (priv->pathname)
471 free(priv->pathname);
472 priv->pathname = NULL;
473 return 0;
476 int mvfs_mixpfs_fileops_free(MVFS_FILE* file)
478 __FILEOPS_HEAD(-1);
479 mvfs_mixpfs_fileops_close(file);
480 free(priv);
481 file->priv.ptr = NULL;
482 return 0;
485 int mvfs_mixpfs_fileops_eof(MVFS_FILE* file)
487 __FILEOPS_HEAD(1);
488 return ((priv->eof) ? 1 : 0);
491 MVFS_FILE* mvfs_mixpfs_fileops_lookup(MVFS_FILE* file, const char* name)
493 __FILEOPS_HEAD(NULL);
495 char* buffer = (char*)calloc(1,strlen(priv->pathname)+strlen(name)+10);
496 sprintf(buffer,"%s/%s", priv->pathname, name);
498 DEBUGMSG("name=\"%s\" oldname=\"%s\" newname=\"%s\"", name, priv->pathname, buffer);
500 MVFS_FILE* newfile = mvfs_mixpfs_fsops_open(file->fs, buffer, O_RDONLY);
501 free(buffer);
502 return newfile;
505 MVFS_STAT* mvfs_mixpfs_fileops_scan(MVFS_FILE* file)
507 __FILEOPS_HEAD(NULL);
508 __mixp_readdir(file);
510 if (priv->dirptr == NULL)
511 return NULL;
513 MIXP_STAT* st = priv->dirptr->stat;
514 if (st == NULL)
516 ERRMSG("UH! got an empty list entry!");
517 return NULL;
520 MVFS_STAT* stat = _convert_stat(st);
521 priv->dirptr = priv->dirptr->next;
522 return stat;
525 int mvfs_mixpfs_fileops_reset(MVFS_FILE* file)
527 __FILEOPS_HEAD(-1);
528 __mixp_readdir(file);
529 priv->dirptr = priv->dirents;
530 return ((priv->dirptr == NULL) ? 0 : 1);