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
12 #include "mvfs-internal.h"
14 #define _LARGEFILE64_SOURCE
16 #include <sys/types.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
)
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
;
100 #ifdef _MVFS_SANITY_CHECKS
102 #define __FILEOPS_HEAD(err); \
105 ERRMSG("NULL file handle"); \
108 MIXP_FILE_PRIV* priv = (file->priv.ptr); \
111 ERRMSG("corrupt file handle"); \
117 #define __FILEOPS_HEAD(err); \
118 MIXP_FILE_PRIV* priv = (file->priv.ptr); \
122 static int __mixp_flushdir(MVFS_FILE
* file
)
124 __FILEOPS_HEAD(-EFAULT
);
126 for (walk
=priv
->dirents
; walk
; walk
=priv
->dirents
)
128 mixp_stat_free(walk
->stat
);
131 priv
->dirents
= priv
->dirptr
= NULL
;
135 static int __mixp_readdir(MVFS_FILE
* file
)
137 __FILEOPS_HEAD(-EFAULT
);
139 // directory already loaded ?
140 if (priv
->dirents
!= NULL
)
150 MIXP_STAT
* stat
= mixp_stat(MIXP_FS_CLIENT(file
->fs
), priv
->pathname
);
153 DEBUGMSG("couldnt stat dir: \"%s\"", priv
->pathname
);
156 if ((stat
->mode
& P9_DMDIR
) == 0)
158 DEBUGMSG("file \"%s\" is not an directory", priv
->pathname
);
159 mixp_stat_free(stat
);
162 mixp_stat_free(stat
);
165 fid
= mixp_open(MIXP_FS_CLIENT(file
->fs
), priv
->pathname
, P9_OREAD
);
168 DEBUGMSG("couldnt open file \"%s\"", priv
->pathname
);
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
);
188 entries
= walk
= (MIXP_DIRENT
*)calloc(1,sizeof(MIXP_DIRENT
));
192 walk
->next
= (MIXP_DIRENT
*)calloc(1,sizeof(MIXP_DIRENT
));
195 walk
->stat
= newstat
;
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
210 case SEEK_SET
: priv
->pos
= offset
; break;
211 case SEEK_CUR
: priv
->pos
+= offset
; break;
213 DEBUGMSG("WARN: 9p/mixp: SEEK_END not implemented yet");
214 file
->errcode
= EINVAL
;
217 DEBUGMSG("WARN: mixp::seek() unknown whence %d", whence
);
218 file
->errcode
= EINVAL
;
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
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
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
);
262 ssize_t
mvfs_mixpfs_fileops_pwrite (MVFS_FILE
* file
, const void* buf
, size_t count
, off64_t offset
)
265 ssize_t s
= mixp_pwrite(priv
->cfid
, buf
, count
, offset
);
270 static inline const char* __mvfs_flag2str(MVFS_FILE_FLAG 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
)
286 DEBUGMSG("%s not supported", __mvfs_flag2str(flag
));
287 file
->errcode
= EINVAL
;
291 int mvfs_mixpfs_fileops_getflag (MVFS_FILE
* file
, MVFS_FILE_FLAG flag
, long* value
)
294 DEBUGMSG("%s not supported", __mvfs_flag2str(flag
));
295 file
->errcode
= EINVAL
;
299 static inline MVFS_STAT
* _convert_stat(MIXP_STAT
* st
)
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
);
314 stat_mvfs
->size
= st
->length
;
315 stat_mvfs
->mtime
= st
->mtime
;
316 stat_mvfs
->atime
= st
->atime
;
317 stat_mvfs
->ctime
= st
->mtime
;
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
;
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
;
339 stat_mvfs
->mode
|= S_IRUSR
;
341 stat_mvfs
->mode
|= S_IWUSR
;
343 stat_mvfs
->mode
|= S_IXUSR
;
345 stat_mvfs
->mode
|= S_IRGRP
;
347 stat_mvfs
->mode
|= S_IWGRP
;
349 stat_mvfs
->mode
|= S_IXGRP
;
351 stat_mvfs
->mode
|= S_IROTH
;
353 stat_mvfs
->mode
|= S_IWOTH
;
355 stat_mvfs
->mode
|= S_IXOTH
;
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
);
366 file
->errcode
= EINVAL
;
373 // FIXME: handle the various file modes !!!
374 MVFS_FILE
* mvfs_mixpfs_fsops_open(MVFS_FILESYSTEM
* fs
, const char* name
, mode_t mode
)
379 else if (mode
& O_WRONLY
)
384 MIXP_CFID
* fid
= mixp_open(MIXP_FS_CLIENT(fs
), name
, m
);
387 DEBUGMSG("couldnt open file: \"%s\"", name
);
388 fs
->errcode
= ENOENT
;
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
;
398 priv
->pathname
= SSTRDUP(name
);
403 MVFS_STAT
* mvfs_mixpfs_fsops_stat(MVFS_FILESYSTEM
* fs
, const char* name
)
407 ERRMSG("NULL fs passed !");
411 MIXP_STAT
* mst
= mixp_stat(MIXP_FS_CLIENT(fs
), name
);
412 MVFS_STAT
* st
= _convert_stat(mst
);
417 fs
->errcode
= EINVAL
;
424 int mvfs_mixpfs_fsops_unlink(MVFS_FILESYSTEM
* fs
, const char* name
)
426 DEBUGMSG("FIXME: DUMMY");
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
);
442 MIXP_SERVER_ADDRESS
* addr
= mixp_srv_addr_parse(url
);
445 ERRMSG("could not parse address \"%s\"", url
);
449 MIXP_CLIENT
* client
= mixp_mount_addr(addr
);
452 ERRMSG("could not mount service @ \"%s\"", url
);
456 MVFS_FILESYSTEM
* fs
= mvfs_fs_alloc(mixpfs_fsops
,FS_MAGIC
);
462 int mvfs_mixpfs_fileops_close(MVFS_FILE
* file
)
466 mixp_close(priv
->cfid
);
471 free(priv
->pathname
);
472 priv
->pathname
= NULL
;
476 int mvfs_mixpfs_fileops_free(MVFS_FILE
* file
)
479 mvfs_mixpfs_fileops_close(file
);
481 file
->priv
.ptr
= NULL
;
485 int mvfs_mixpfs_fileops_eof(MVFS_FILE
* file
)
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
);
505 MVFS_STAT
* mvfs_mixpfs_fileops_scan(MVFS_FILE
* file
)
507 __FILEOPS_HEAD(NULL
);
508 __mixp_readdir(file
);
510 if (priv
->dirptr
== NULL
)
513 MIXP_STAT
* st
= priv
->dirptr
->stat
;
516 ERRMSG("UH! got an empty list entry!");
520 MVFS_STAT
* stat
= _convert_stat(st
);
521 priv
->dirptr
= priv
->dirptr
->next
;
525 int mvfs_mixpfs_fileops_reset(MVFS_FILE
* file
)
528 __mixp_readdir(file
);
529 priv
->dirptr
= priv
->dirents
;
530 return ((priv
->dirptr
== NULL
) ? 0 : 1);