/* * Copyright © 2007 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman */ #include #include #include #include #include #include #include #include #include static CompMetadata fuseMetadata; #define FUSE_INODE_TYPE_ROOT (1 << 0) #define FUSE_INODE_TYPE_PLUGIN (1 << 1) #define FUSE_INODE_TYPE_SCREEN (1 << 2) #define FUSE_INODE_TYPE_DISPLAY (1 << 3) #define FUSE_INODE_TYPE_OPTION (1 << 4) #define FUSE_INODE_TYPE_TYPE (1 << 5) #define FUSE_INODE_TYPE_VALUE (1 << 6) #define FUSE_INODE_TYPE_ITEM_COUNT (1 << 7) #define FUSE_INODE_TYPE_ITEM_TYPE (1 << 8) #define FUSE_INODE_TYPE_ITEMS (1 << 9) #define FUSE_INODE_TYPE_ITEM_VALUE (1 << 10) #define FUSE_INODE_TYPE_MIN (1 << 11) #define FUSE_INODE_TYPE_MAX (1 << 12) #define FUSE_INODE_TYPE_PRECISION (1 << 13) #define DIR_MASK (FUSE_INODE_TYPE_ROOT | \ FUSE_INODE_TYPE_PLUGIN | \ FUSE_INODE_TYPE_SCREEN | \ FUSE_INODE_TYPE_DISPLAY | \ FUSE_INODE_TYPE_OPTION | \ FUSE_INODE_TYPE_ITEMS) #define CONST_DIR_MASK (FUSE_INODE_TYPE_PLUGIN | \ FUSE_INODE_TYPE_SCREEN | \ FUSE_INODE_TYPE_DISPLAY | \ FUSE_INODE_TYPE_OPTION) #define WRITE_MASK (FUSE_INODE_TYPE_VALUE | \ FUSE_INODE_TYPE_ITEM_VALUE) #define FUSE_INODE_FLAG_TRUNC (1 << 0) typedef struct _FuseInode { struct _FuseInode *parent; struct _FuseInode *child; struct _FuseInode *sibling; int type; int flags; fuse_ino_t ino; char *name; } FuseInode; typedef struct _FuseWriteBuffer { char *data; int size; Bool dirty; } FuseWriteBuffer; static int displayPrivateIndex; #define FUSE_DISPLAY_OPTION_MOUNT_POINT 0 #define FUSE_DISPLAY_OPTION_NUM 1 typedef struct _FuseDisplay { CompOption opt[FUSE_DISPLAY_OPTION_NUM]; struct fuse_session *session; struct fuse_chan *channel; char *mountPoint; CompWatchFdHandle watchFdHandle; char *buffer; } FuseDisplay; #define GET_FUSE_DISPLAY(d) \ ((FuseDisplay *) (d)->base.privates[displayPrivateIndex].ptr) #define FUSE_DISPLAY(d) \ FuseDisplay *fd = GET_FUSE_DISPLAY (d) #define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption)) static fuse_ino_t nextIno = 1; static FuseInode *inodes = NULL; static FuseInode * fuseAddInode (FuseInode *parent, int type, const char *name) { FuseInode *inode; inode = malloc (sizeof (FuseInode)); if (!inode) return NULL; inode->parent = parent; inode->sibling = NULL; inode->child = NULL; inode->type = type; inode->flags = 0; inode->ino = nextIno++; inode->name = strdup (name); if (parent) { if (parent->child) inode->sibling = parent->child; parent->child = inode; } return inode; } static void fuseRemoveInode (FuseInode *parent, FuseInode *inode) { while (inode->child) fuseRemoveInode (inode, inode->child); if (parent) { FuseInode *s, *prev = NULL; for (s = parent->child; s; s = s->sibling) { if (s == inode) break; prev = s; } if (prev) prev->sibling = inode->sibling; else parent->child = NULL; } if (inode->name) free (inode->name); free (inode); } static FuseInode * fuseFindInode (FuseInode *inode, fuse_ino_t ino, int mask) { if (inode->ino != ino) { FuseInode *c = inode->child; inode = NULL; while (c) { inode = fuseFindInode (c, ino, ~0); if (inode) break; c = c->sibling; } } if (inode && (inode->type & mask)) return inode; return NULL; } static FuseInode * fuseLookupChild (FuseInode *inode, const char *name) { FuseInode *c; for (c = inode->child; c; c = c->sibling) if (strcmp (c->name, name) == 0) return c; return NULL; } /* MULTIDPYERROR: only works with one or less displays present */ /* OBJECTOPTION: only display and screen options are supported */ static CompObject * fuseGetObjectFromInode (FuseInode *inode) { CompObject *object; object = compObjectFind (&core.base, COMP_OBJECT_TYPE_DISPLAY, NULL); if (!object) return NULL; if (inode->type & FUSE_INODE_TYPE_SCREEN) { return compObjectFind (object, COMP_OBJECT_TYPE_SCREEN, inode->name + 6); } else if (inode->type & FUSE_INODE_TYPE_DISPLAY) { return object; } return NULL; } static CompOption * fuseGetOptionsFromInode (CompObject *object, FuseInode *inode, int *nOption) { CompOption *option = NULL; if (inode->type & FUSE_INODE_TYPE_PLUGIN) { CompPlugin *p; p = findActivePlugin (inode->name); if (p && p->vTable->getObjectOptions) option = (*p->vTable->getObjectOptions) (p, object, nOption); } return option; } static CompOption * fuseGetOptionFromInode (FuseInode *inode) { if (inode->type & (FUSE_INODE_TYPE_OPTION | FUSE_INODE_TYPE_ITEMS)) { CompObject *object; CompOption *option; int nOption; if (inode->type & FUSE_INODE_TYPE_ITEMS) inode = inode->parent; object = fuseGetObjectFromInode (inode); if (!object) return NULL; option = fuseGetOptionsFromInode (object, inode->parent, &nOption); if (option) { while (nOption--) { if (strcmp (inode->name, option->name) == 0) return option; option++; } } } return NULL; } /* MULTIDPYERROR: only works with one or less displays present */ static char * fuseGetStringFromInode (FuseInode *inode) { CompOption *option; char str[256]; if (!inode->parent) return NULL; option = fuseGetOptionFromInode (inode->parent); if (!option) return NULL; if (inode->flags & FUSE_INODE_FLAG_TRUNC) return strdup (""); if (inode->type & FUSE_INODE_TYPE_TYPE) { return strdup (optionTypeToString (option->type)); } else if (inode->type & (FUSE_INODE_TYPE_VALUE | FUSE_INODE_TYPE_ITEM_VALUE)) { CompOptionValue *value = NULL; CompOptionType type; if (inode->type & FUSE_INODE_TYPE_ITEM_VALUE) { int i; if (sscanf (inode->name, "value%d", &i)) { if (i < option->value.list.nValue) { value = &option->value.list.value[i]; type = option->value.list.type; } } } else { value = &option->value; type = option->type; } if (value) { switch (type) { case CompOptionTypeBool: return strdup (value->b ? "true" : "false"); case CompOptionTypeInt: snprintf (str, 256, "%d", value->i); return strdup (str); case CompOptionTypeFloat: snprintf (str, 256, "%f", value->f); return strdup (str); case CompOptionTypeString: return strdup (value->s); case CompOptionTypeColor: return colorToString (value->c); case CompOptionTypeKey: if (core.displays) return keyActionToString (core.displays, &value->action); case CompOptionTypeButton: if (core.displays) return buttonActionToString (core.displays, &value->action); case CompOptionTypeEdge: return edgeMaskToString (value->action.edgeMask); case CompOptionTypeBell: return strdup (value->action.bell ? "true" : "false"); case CompOptionTypeMatch: return matchToString (&value->match); default: break; } } } else if (inode->type & FUSE_INODE_TYPE_MIN) { if (option->type == CompOptionTypeInt) snprintf (str, 256, "%d", option->rest.i.min); else snprintf (str, 256, "%f", option->rest.f.min); return strdup (str); } else if (inode->type & FUSE_INODE_TYPE_MAX) { if (option->type == CompOptionTypeInt) snprintf (str, 256, "%d", option->rest.i.max); else snprintf (str, 256, "%f", option->rest.f.max); return strdup (str); } else if (inode->type & FUSE_INODE_TYPE_PRECISION) { snprintf (str, 256, "%f", option->rest.f.precision); return strdup (str); } else if (inode->type & FUSE_INODE_TYPE_ITEM_COUNT) { snprintf (str, 256, "%d", option->value.list.nValue); return strdup (str); } else if (inode->type & FUSE_INODE_TYPE_ITEM_TYPE) { return strdup (optionTypeToString (option->value.list.type)); } return NULL; } static void fuseUpdateInode (CompDisplay *d, FuseInode *inode) { CompScreen *s; CompPlugin *p; CompOption *option; char str[256]; if (inode->type & FUSE_INODE_TYPE_ROOT) { FuseInode *c; for (c = inode->child; c; c = c->sibling) { if (!findActivePlugin (c->name)) fuseRemoveInode (inode, c); } for (p = getPlugins (); p; p = p->next) if (!fuseLookupChild (inode, p->vTable->name)) fuseAddInode (inode, FUSE_INODE_TYPE_PLUGIN, p->vTable->name); } else if (inode->type & FUSE_INODE_TYPE_PLUGIN) { int n; if (fuseGetOptionsFromInode (&d->base, inode, &n)) fuseAddInode (inode, FUSE_INODE_TYPE_DISPLAY, "allscreens"); for (s = d->screens; s; s = s->next) { if (fuseGetOptionsFromInode (&s->base, inode, &n)) { sprintf (str, "screen%d", s->screenNum); fuseAddInode (inode, FUSE_INODE_TYPE_SCREEN, str); } } } else if (inode->type & (FUSE_INODE_TYPE_DISPLAY | FUSE_INODE_TYPE_SCREEN)) { CompObject *object; object = fuseGetObjectFromInode (inode); if (object) { int nOption; option = fuseGetOptionsFromInode (object, inode->parent, &nOption); if (option) { while (nOption--) { fuseAddInode (inode, FUSE_INODE_TYPE_OPTION, option->name); option++; } } } } else if (inode->type & FUSE_INODE_TYPE_OPTION) { option = fuseGetOptionFromInode (inode); if (option) { fuseAddInode (inode, FUSE_INODE_TYPE_TYPE, "type"); switch (option->type) { case CompOptionTypeFloat: fuseAddInode (inode, FUSE_INODE_TYPE_PRECISION, "precision"); /* fall-through */ case CompOptionTypeInt: fuseAddInode (inode, FUSE_INODE_TYPE_MIN, "min"); fuseAddInode (inode, FUSE_INODE_TYPE_MAX, "max"); /* fall-through */ case CompOptionTypeBool: case CompOptionTypeString: case CompOptionTypeColor: case CompOptionTypeKey: case CompOptionTypeButton: case CompOptionTypeEdge: case CompOptionTypeBell: case CompOptionTypeMatch: fuseAddInode (inode, FUSE_INODE_TYPE_VALUE, "value"); break; case CompOptionTypeList: fuseAddInode (inode, FUSE_INODE_TYPE_ITEMS, "items"); fuseAddInode (inode, FUSE_INODE_TYPE_ITEM_COUNT, "number_of_items"); fuseAddInode (inode, FUSE_INODE_TYPE_ITEM_TYPE, "item_type"); default: break; } } } else if (inode->type & FUSE_INODE_TYPE_ITEMS) { option = fuseGetOptionFromInode (inode->parent); if (option && option->type == CompOptionTypeList) { FuseInode *c, *next; int i, nValue = option->value.list.nValue; for (i = 0; i < option->value.list.nValue; i++) { sprintf (str, "value%d", i); if (!fuseLookupChild (inode, str)) fuseAddInode (inode, FUSE_INODE_TYPE_ITEM_VALUE, str); } for (c = inode->child; c; c = next) { next = c->sibling; if (sscanf (c->name, "value%d", &i) == 0 || i >= nValue) fuseRemoveInode (inode, c); } } } } static void fuseInodeStat (CompDisplay *d, FuseInode *inode, struct stat *stbuf) { stbuf->st_ino = inode->ino; if (inode->type & DIR_MASK) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; } else { char *str; if (inode->type & WRITE_MASK) stbuf->st_mode = S_IFREG | 0666; else stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = 0; str = fuseGetStringFromInode (inode); if (str) { stbuf->st_size = strlen (str); free (str); } } } static Bool fuseInitValue (CompOptionValue *value, CompOptionType type, CompOptionValue *src) { switch (type) { case CompOptionTypeBool: value->b = src->b; break; case CompOptionTypeInt: value->i = src->i; break; case CompOptionTypeFloat: value->f = src->f; break; case CompOptionTypeString: value->s = strdup (src->s); break; case CompOptionTypeColor: memcpy (value->c, src->c, sizeof (*src->c)); break; case CompOptionTypeKey: case CompOptionTypeButton: case CompOptionTypeEdge: case CompOptionTypeBell: value->action = src->action; break; case CompOptionTypeMatch: matchInit (&value->match); matchCopy (&value->match, &src->match); break; default: return FALSE; } return TRUE; } static Bool fuseInitValueFromString (CompObject *object, CompOptionValue *value, CompOptionType type, char *str) { switch (type) { case CompOptionTypeBool: value->b = strcmp (str, "true") ? FALSE : TRUE; break; case CompOptionTypeInt: value->i = atoi (str); break; case CompOptionTypeFloat: value->f = strtod (str, NULL); break; case CompOptionTypeString: value->s = strdup (str); break; case CompOptionTypeColor: if (!stringToColor (str, value->c)) return FALSE; break; case CompOptionTypeKey: while (object && object->type != COMP_OBJECT_TYPE_DISPLAY) object = object->parent; if (!object) return FALSE; stringToKeyAction (GET_CORE_DISPLAY (object), str, &value->action); break; case CompOptionTypeButton: while (object && object->type != COMP_OBJECT_TYPE_DISPLAY) object = object->parent; if (!object) return FALSE; stringToButtonAction (GET_CORE_DISPLAY (object), str, &value->action); break; case CompOptionTypeEdge: value->action.edgeMask = stringToEdgeMask (str); break; case CompOptionTypeBell: value->action.bell = strcmp (str, "true") ? FALSE : TRUE; break; case CompOptionTypeMatch: matchInit (&value->match); matchAddFromString (&value->match, str); break; default: return FALSE; } return TRUE; } static void fuseSetInodeOptionUsingString (FuseInode *inode, char *str) { CompOption *option; option = fuseGetOptionFromInode (inode->parent); if (option) { CompOptionValue value; CompObject *object; const char *pluginName; if (inode->type & FUSE_INODE_TYPE_VALUE) { object = fuseGetObjectFromInode (inode->parent->parent); if (!object) return; if (!fuseInitValueFromString (object, &value, option->type, str)) return; pluginName = inode->parent->parent->parent->name; } else if (inode->type & FUSE_INODE_TYPE_ITEM_VALUE) { int i, item, nValue = option->value.list.nValue; if (!sscanf (inode->name, "value%d", &item)) return; if (item >= nValue) return; object = fuseGetObjectFromInode (inode->parent->parent->parent); if (!object) return; value.list.value = malloc (sizeof (CompOptionValue) * nValue); if (!value.list.value) return; value.list.type = option->value.list.type; value.list.nValue = 0; for (i = 0; i < nValue; i++) { if (i == item) { if (!fuseInitValueFromString (object, &value.list.value[i], value.list.type, str)) break; } else { if (!fuseInitValue (&value.list.value[i], value.list.type, &option->value.list.value[i])) break; } value.list.nValue++; } /* failed */ if (value.list.nValue < nValue) { compFiniOptionValue (&value, option->type); return; } pluginName = inode->parent->parent->parent->parent->name; } else { return; } (*core.setOptionForPlugin) (object, pluginName, option->name, &value); compFiniOptionValue (&value, option->type); } } static void compiz_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CompDisplay *d = (CompDisplay *) fuse_req_userdata (req); FuseInode *inode; inode = fuseFindInode (inodes, ino, ~0); if (inode) { struct stat stbuf; memset (&stbuf, 0, sizeof (stbuf)); fuseInodeStat (d, inode, &stbuf); fuse_reply_attr (req, &stbuf, 1.0); } else { fuse_reply_err (req, ENOENT); } } static void compiz_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { CompDisplay *d = (CompDisplay *) fuse_req_userdata (req); FuseInode *inode; inode = fuseFindInode (inodes, ino, WRITE_MASK); if (inode) { struct stat stbuf; if ((to_set & FUSE_SET_ATTR_SIZE) != FUSE_SET_ATTR_SIZE) { fuse_reply_err (req, EACCES); return; } if (attr->st_size != 0) { fuse_reply_err (req, EACCES); return; } inode->flags |= FUSE_INODE_FLAG_TRUNC; memset (&stbuf, 0, sizeof (stbuf)); fuseInodeStat (d, inode, &stbuf); fuse_reply_attr (req, &stbuf, 1.0); } else { fuse_reply_err (req, ENOENT); } } static void compiz_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) { CompDisplay *d = (CompDisplay *) fuse_req_userdata (req); FuseInode *inode; struct fuse_entry_param e; inode = fuseFindInode (inodes, parent, DIR_MASK); if (!inode) { fuse_reply_err (req, ENOENT); return; } if (!inode->child || !(inode->type & CONST_DIR_MASK)) fuseUpdateInode (d, inode); inode = fuseLookupChild (inode, name); if (!inode) { fuse_reply_err (req, ENOENT); return; } memset (&e, 0, sizeof (e)); e.attr_timeout = 1.0; e.entry_timeout = 1.0; e.ino = inode->ino; fuseInodeStat (d, inode, &e.attr); fuse_reply_entry (req, &e); } struct dirbuf { char *p; size_t size; }; static void dirbuf_add (fuse_req_t req, struct dirbuf *b, const char *name, fuse_ino_t ino) { struct stat stbuf; size_t oldSize = b->size; b->size += fuse_add_direntry (req, NULL, 0, name, NULL, 0); b->p = (char *) realloc (b->p, b->size); memset (&stbuf, 0, sizeof (stbuf)); stbuf.st_ino = ino; fuse_add_direntry (req, b->p + oldSize, b->size - oldSize, name, &stbuf, b->size); } static int reply_buf_limited (fuse_req_t req, const char *buf, size_t bufsize, off_t off, size_t maxsize) { if (off < bufsize) return fuse_reply_buf (req, buf + off, MIN (bufsize - off, maxsize)); else return fuse_reply_buf (req, NULL, 0); } static void compiz_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { CompDisplay *d = (CompDisplay *) fuse_req_userdata (req); FuseInode *inode, *c; struct dirbuf b; inode = fuseFindInode (inodes, ino, DIR_MASK); if (!inode) { fuse_reply_err (req, ENOTDIR); return; } memset (&b, 0, sizeof (b)); dirbuf_add (req, &b, ".", ino); dirbuf_add (req, &b, "..", inode->parent ? inode->parent->ino : ino); if (!inode->child || !(inode->type & CONST_DIR_MASK)) fuseUpdateInode (d, inode); for (c = inode->child; c; c = c->sibling) dirbuf_add (req, &b, c->name, c->ino); reply_buf_limited (req, b.p, b.size, off, size); free (b.p); } static void compiz_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { FuseInode *inode; inode = fuseFindInode (inodes, ino, ~0); if (!inode) { fuse_reply_err (req, ENOENT); return; } fi->fh = 0; if (inode->type & DIR_MASK) { fuse_reply_err (req, EISDIR); } else if (inode->type & WRITE_MASK) { if ((fi->flags & 3) != O_RDONLY) { char *data; if (fi->flags & O_TRUNC) data = strdup (""); else data = fuseGetStringFromInode (inode); if (data) { FuseWriteBuffer *wb; wb = malloc (sizeof (FuseWriteBuffer)); if (wb) { wb->data = data; wb->size = strlen (wb->data); wb->dirty = TRUE; fi->fh = (unsigned long) wb; } else { free (data); } } } fuse_reply_open (req, fi); } else if ((fi->flags & 3) != O_RDONLY) { fuse_reply_err (req, EACCES); } else { fuse_reply_open (req, fi); } } static void compiz_read (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { FuseInode *inode; char *str = NULL; inode = fuseFindInode (inodes, ino, ~0); if (inode) str = fuseGetStringFromInode (inode); if (str) { reply_buf_limited (req, str, strlen (str), off, size); free (str); } else { reply_buf_limited (req, NULL, 0, off, size); } } static void compiz_write (fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { FuseInode *inode; inode = fuseFindInode (inodes, ino, WRITE_MASK); if (inode && fi->fh) { FuseWriteBuffer *wb = (FuseWriteBuffer *) (uintptr_t) fi->fh; if (off + size > wb->size) { char *data; data = realloc (wb->data, off + size + 1); if (!data) { fuse_reply_err (req, ENOBUFS); return; } data[off + size] = '\0'; wb->data = data; wb->size = off + size; } memcpy (wb->data + off, buf, size); wb->dirty = TRUE; fuse_reply_write (req, size); } else { fuse_reply_err (req, ENOENT); } } static void compiz_release (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { if (fi->fh) { FuseWriteBuffer *wb = (FuseWriteBuffer *) (uintptr_t) fi->fh; FuseInode *inode; inode = fuseFindInode (inodes, ino, WRITE_MASK); if (inode && wb->dirty) { fuseSetInodeOptionUsingString (inode, wb->data); inode->flags &= ~FUSE_INODE_FLAG_TRUNC; } free (wb->data); free (wb); } fuse_reply_err (req, 0); } static void compiz_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { if (fi->fh) { FuseWriteBuffer *wb = (FuseWriteBuffer *) (uintptr_t) fi->fh; FuseInode *inode; inode = fuseFindInode (inodes, ino, WRITE_MASK); if (inode && wb->dirty) { fuseSetInodeOptionUsingString (inode, wb->data); inode->flags &= ~FUSE_INODE_FLAG_TRUNC; wb->dirty = FALSE; } } fuse_reply_err (req, 0); } static struct fuse_lowlevel_ops compiz_ll_oper = { .lookup = compiz_lookup, .getattr = compiz_getattr, .setattr = compiz_setattr, .readdir = compiz_readdir, .open = compiz_open, .read = compiz_read, .write = compiz_write, .release = compiz_release, .fsync = compiz_fsync }; static void fuseUnmount (CompDisplay *d) { FUSE_DISPLAY (d); if (fd->watchFdHandle) { compRemoveWatchFd (fd->watchFdHandle); fd->watchFdHandle = 0; } if (fd->mountPoint) { /* unmount will destroy the channel */ fuse_unmount (fd->mountPoint, fd->channel); free (fd->mountPoint); fd->mountPoint = NULL; fd->channel = NULL; } if (fd->buffer) { free (fd->buffer); fd->buffer = NULL; } } static Bool fuseProcessMessages (void *data) { CompDisplay *d = (CompDisplay *) data; struct fuse_chan *channel; size_t bufferSize; int res = 0; FUSE_DISPLAY (d); channel = fuse_session_next_chan (fd->session, NULL); bufferSize = fuse_chan_bufsize (channel); if (fuse_session_exited (fd->session)) return FALSE; for (;;) { struct fuse_chan *tmpch = channel; res = fuse_chan_recv (&tmpch, fd->buffer, bufferSize); if (res == -EINTR) continue; if (res > 0) fuse_session_process (fd->session, fd->buffer, res, tmpch); break; } return TRUE; } static void fuseMount (CompDisplay *d) { char *mountPoint; struct fuse_args args = FUSE_ARGS_INIT (0, NULL); FUSE_DISPLAY (d); mountPoint = strdup (fd->opt[FUSE_DISPLAY_OPTION_MOUNT_POINT].value.s); if (!mountPoint) return; fuse_opt_add_arg (&args, ""); fuse_opt_add_arg (&args, "-o"); fuse_opt_add_arg (&args, "allow_root"); fd->channel = fuse_mount (mountPoint, &args); if (!fd->channel) { fuse_opt_free_args (&args); free (mountPoint); return; } fuse_opt_free_args (&args); fd->buffer = malloc (fuse_chan_bufsize (fd->channel)); if (!fd->buffer) { fuse_unmount (mountPoint, fd->channel); free (mountPoint); fd->channel = NULL; return; } fd->mountPoint = mountPoint; fuse_session_add_chan (fd->session, fd->channel); fd->watchFdHandle = compAddWatchFd (fuse_chan_fd (fd->channel), POLLIN | POLLPRI | POLLHUP | POLLERR, fuseProcessMessages, d); } static CompOption * fuseGetDisplayOptions (CompPlugin *plugin, CompDisplay *display, int *count) { FUSE_DISPLAY (display); *count = NUM_OPTIONS (fd); return fd->opt; } static Bool fuseSetDisplayOption (CompPlugin *plugin, CompDisplay *display, const char *name, CompOptionValue *value) { CompOption *o; int index; FUSE_DISPLAY (display); o = compFindOption (fd->opt, NUM_OPTIONS (fd), name, &index); if (!o) return FALSE; switch (index) { case FUSE_DISPLAY_OPTION_MOUNT_POINT: if (compSetStringOption (o, value)) { fuseUnmount (display); fuseMount (display); return TRUE; } default: break; } return FALSE; } static const CompMetadataOptionInfo fuseDisplayOptionInfo[] = { { "mount_point", "string", 0, 0, 0 } }; static Bool fuseInitDisplay (CompPlugin *p, CompDisplay *d) { FuseDisplay *fd; struct sigaction sa; if (!checkPluginABI ("core", CORE_ABIVERSION)) return FALSE; memset (&sa, 0, sizeof (struct sigaction)); sa.sa_handler = SIG_IGN; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; if (sigaction (SIGPIPE, &sa, NULL) == -1) return FALSE; fd = malloc (sizeof (FuseDisplay)); if (!fd) return FALSE; if (!compInitDisplayOptionsFromMetadata (d, &fuseMetadata, fuseDisplayOptionInfo, fd->opt, FUSE_DISPLAY_OPTION_NUM)) { free (fd); return FALSE; } fd->session = fuse_lowlevel_new (NULL, &compiz_ll_oper, sizeof (compiz_ll_oper), (void *) d); if (!fd->session) { compFiniDisplayOptions (d, fd->opt, FUSE_DISPLAY_OPTION_NUM); free (fd); return FALSE; } fd->watchFdHandle = 0; fd->channel = NULL; fd->buffer = NULL; fd->mountPoint = NULL; d->base.privates[displayPrivateIndex].ptr = fd; fuseMount (d); return TRUE; } static void fuseFiniDisplay (CompPlugin *p, CompDisplay *d) { FUSE_DISPLAY (d); fuseUnmount (d); fuse_session_destroy (fd->session); compFiniDisplayOptions (d, fd->opt, FUSE_DISPLAY_OPTION_NUM); free (fd); } static Bool fuseInit (CompPlugin *p) { if (!compInitPluginMetadataFromInfo (&fuseMetadata, p->vTable->name, fuseDisplayOptionInfo, FUSE_DISPLAY_OPTION_NUM, 0, 0)) return FALSE; inodes = fuseAddInode (NULL, FUSE_INODE_TYPE_ROOT, "."); if (!inodes) { compFiniMetadata (&fuseMetadata); return FALSE; } displayPrivateIndex = allocateDisplayPrivateIndex (); if (displayPrivateIndex < 0) { fuseRemoveInode (NULL, inodes); compFiniMetadata (&fuseMetadata); return FALSE; } compAddMetadataFromFile (&fuseMetadata, p->vTable->name); return TRUE; } static CompBool fuseInitObject (CompPlugin *p, CompObject *o) { static InitPluginObjectProc dispTab[] = { (InitPluginObjectProc) 0, /* InitCore */ (InitPluginObjectProc) fuseInitDisplay }; RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o)); } static void fuseFiniObject (CompPlugin *p, CompObject *o) { static FiniPluginObjectProc dispTab[] = { (FiniPluginObjectProc) 0, /* FiniCore */ (FiniPluginObjectProc) fuseFiniDisplay }; DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o)); } static CompOption * fuseGetObjectOptions (CompPlugin *plugin, CompObject *object, int *count) { static GetPluginObjectOptionsProc dispTab[] = { (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */ (GetPluginObjectOptionsProc) fuseGetDisplayOptions }; RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), (void *) (*count = 0), (plugin, object, count)); } static CompBool fuseSetObjectOption (CompPlugin *plugin, CompObject *object, const char *name, CompOptionValue *value) { static SetPluginObjectOptionProc dispTab[] = { (SetPluginObjectOptionProc) 0, /* SetCoreOption */ (SetPluginObjectOptionProc) fuseSetDisplayOption }; RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE, (plugin, object, name, value)); } static void fuseFini (CompPlugin *p) { fuseRemoveInode (NULL, inodes); freeDisplayPrivateIndex (displayPrivateIndex); compFiniMetadata (&fuseMetadata); } static CompMetadata * fuseGetMetadata (CompPlugin *plugin) { return &fuseMetadata; } CompPluginVTable fuseVTable = { "fs", fuseGetMetadata, fuseInit, fuseFini, fuseInitObject, fuseFiniObject, fuseGetObjectOptions, fuseSetObjectOption }; CompPluginVTable * getCompPluginInfo20070830 (void) { return &fuseVTable; }