static Npfcall * np_attach(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid, *afid; Npfcall *rc; rc = NULL; conn = req->conn; afid = NULL; /* the fid that the connecting client wants to call root */ fid = np_fid_find(conn, tc->fid); /* if this fid exists then report error */ if (fid) { np_werror(Einuse, EIO); goto done; } /* create a fid structure for the root */ fid = np_fid_create(conn, tc->fid, NULL); if (!fid) { np_werror(Enomem, ENOMEM); goto done; } else /* maintain a reference count for fid */ np_fid_incref(fid); req->fid = fid; afid = np_fid_find(conn, tc->afid); if (!afid) { if (tc->afid!=NOFID) { np_werror(Eunknownfid, EIO); goto done; } if (!afid->type&Qtauth) { np_werror(Ebadusefid, EIO); goto done; } } else np_fid_incref(afid); if (conn->srv->auth) { rc = (*conn->srv->auth->attach)(afid, &tc->uname, &tc->aname); if (rc) goto done; } rc = (*conn->srv->attach)(fid, afid, &tc->uname, &tc->aname); done: np_fid_decref(fid); np_fid_decref(afid); return rc; }
static Npfcall* openssl_auth(Npfid *afid, Npstr *uname, Npstr *aname) { struct openssl_session_auth_context* ctx; Npqid aqid; ctx = new_session_context(afid); if ( ctx == NULL ) return np_create_rerror("No mem",ENOMEM,1); ctx->uname = malloc(uname->len); if ( !ctx->uname ) return np_create_rerror("No mem",ENOMEM,1); memcpy(ctx->uname, uname->str, uname->len); afid->aux = ctx; np_fid_incref(afid); pthread_create(&ctx->auth_thread, NULL, run_auth, ctx); aqid.type = Qtauth; return np_create_rauth(&aqid); //return execute_openssl_auth_protocol(ctx); }
static Npfcall * np_open(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (fid->omode != (u16)~0) { np_werror(Ebadusefid, EIO); goto done; } if (fid->type&Qtdir && tc->mode != Oread) { np_werror(Eperm, EPERM); goto done; } rc = (*conn->srv->open)(fid, tc->mode); fid->omode = tc->mode; done: np_fid_decref(fid); return rc; }
/* Create a fid with initial refcount of 1. */ Npfid * np_fid_create (Npconn *conn, u32 fid) { Npsrv *srv = conn->srv; Npfidpool *pool = conn->fidpool; int hash = fid % pool->size; Npfid *f; xpthread_mutex_lock(&pool->lock); if ((f = _lookup_fid (&pool->htable[hash], fid))) { np_logmsg (srv, "np_fid_create: unclunked fid %d (%s): %d refs", f->fid, srv->get_path ? srv->get_path (f) : "<nil>", f->refcount); if ((srv->flags & SRV_FLAGS_LOOSEFID)) { f->flags |= FID_FLAGS_ZOMBIE; } else { np_uerror (EEXIST); f = NULL; goto done; } } if ((f = _create_fid (conn, fid))) { np_fid_incref (f); _link_fid (&pool->htable[hash], f); } done: xpthread_mutex_unlock(&pool->lock); return f; }
Npfcall * np_xattrwalk(Npreq *req, Npfcall *tc) { Npfid *fid = req->fid; Npfid *attrfid; Npfcall *rc = NULL; if (!fid) { np_uerror (EIO); goto done; } if (!(attrfid = np_fid_find(req->conn, tc->u.txattrwalk.attrfid))) { np_uerror(EIO); goto done; } np_fid_incref(attrfid); /* XXX decref needed? */ if (fid->type & P9_QTTMP) { np_uerror (EPERM); goto done; } else { if (np_setfsid (req, fid->user, -1) < 0) goto done; if (!req->conn->srv->xattrwalk) { np_uerror (ENOSYS); goto done; } rc = (*req->conn->srv->xattrwalk)(fid, attrfid, &tc->u.txattrwalk.name); } done: return rc; }
Npfcall * np_rename(Npreq *req, Npfcall *tc) { Npfid *fid = req->fid; Npfid *dfid = NULL; Npfcall *rc = NULL; if (!fid) { np_uerror (EIO); goto done; } if (!(dfid = np_fid_find(req->conn, tc->u.trename.dfid))) { np_uerror(EIO); goto done; } np_fid_incref(dfid); if (fid->type & P9_QTTMP) { np_uerror (EPERM); goto done; } else { if (np_setfsid (req, fid->user, -1) < 0) goto done; if (!req->conn->srv->rename) { np_uerror (ENOSYS); goto done; } rc = (*req->conn->srv->rename)(fid, dfid, &tc->u.trename.name); } done: np_fid_decref(dfid); return rc; }
static Npfcall * np_read(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto error; } else np_fid_incref(fid); req->fid = fid; if (tc->count+IOHDRSZ > conn->msize) { np_werror(Etoolarge, EIO); goto error; } if (fid->type&Qtauth) { if (conn->srv->auth) rc = conn->srv->auth->read(fid, tc->offset, tc->count); else np_werror(Ebadusefid, EIO); goto error; } if (fid->omode==(u16)~0 || (fid->omode&3)==Owrite) { np_werror(Ebadusefid, EIO); goto error; } if (fid->type&Qtdir && tc->offset != fid->diroffset) { np_werror(Ebadoffset, EIO); goto error; } rc = (*conn->srv->read)(fid, tc->offset, tc->count, req); /* if (rc && rc->id==Rread && fid->type&Qtdir) { fid->diroffset = tc->offset + rc->count; } */ if (rc || np_haserror()) np_fid_decref(fid); return rc; error: np_fid_decref(fid); return NULL; }
Npfcall * np_auth(Npreq *req, Npfcall *tc) { Npconn *conn = req->conn; Npsrv *srv = conn->srv; Npfid *afid = req->fid; Npfcall *rc = NULL; Npqid aqid; char a[128]; int auth_required = _authrequired(srv, &tc->u.tauth.uname, tc->u.tauth.n_uname, &tc->u.tauth.aname); if (tc->u.tauth.n_uname != P9_NONUNAME) { snprintf (a, sizeof(a), "auth(%d@%s:%.*s)", tc->u.tauth.n_uname, np_conn_get_client_id (conn), tc->u.tauth.aname.len, tc->u.tauth.aname.str); } else { snprintf (a, sizeof(a), "auth(%.*s@%s:%.*s)", tc->u.tauth.uname.len, tc->u.tauth.uname.str, np_conn_get_client_id (conn), tc->u.tauth.aname.len, tc->u.tauth.aname.str); } if (!auth_required) { if (!(rc = np_create_rlerror(0))) { np_uerror(ENOMEM); np_logerr (srv, "%s: creating response", a); } goto error; } if (!afid) { np_uerror (EIO); np_logerr (srv, "%s: invalid afid (%d)", a, tc->u.tauth.afid); goto error; } np_fid_incref(afid); if (!(afid->user = np_attach2user (srv, &tc->u.tauth.uname, tc->u.tauth.n_uname))) { np_logerr (srv, "%s: user lookup", a); goto error; } afid->type = P9_QTAUTH; if (!srv->auth->startauth(afid, afid->aname, &aqid)) { np_logerr (srv, "%s: startauth", a); goto error; } assert((aqid.type & P9_QTAUTH)); if (!(rc = np_create_rauth(&aqid))) { np_uerror(ENOMEM); np_logerr (srv, "%s: creating response", a); goto error; } error: return rc; }
static Npfcall * myattach (Npfid *fid, Npfid *afid, Npstr *aname) { Npqid qid = { 1, 2, 3}; Npfcall *ret = NULL; if (!(ret = np_create_rattach(&qid))) { np_uerror (ENOMEM); return NULL; } np_fid_incref (fid); return ret; }
/* Find a fid, then refcount++ */ Npfid * np_fid_find (Npconn *conn, u32 fid) { Npfidpool *pool = conn->fidpool; int hash = fid % pool->size; Npfid *f; xpthread_mutex_lock (&pool->lock); if ((f = _lookup_fid (&pool->htable[hash], fid))) np_fid_incref (f); xpthread_mutex_unlock (&pool->lock); return f; }
static Npfcall * np_write(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto error; } else np_fid_incref(fid); req->fid = fid; if (fid->type&Qtauth) { if (conn->srv->auth) { rc = conn->srv->auth->write(fid, tc->offset, tc->count, tc->data); np_fid_decref(fid); return rc; } else { np_werror(Ebadusefid, EIO); goto error; } } if (fid->omode==(u16)~0 || fid->type&Qtdir || (fid->omode&3)==Oread) { np_werror(Ebadusefid, EIO); goto error; } if (tc->count+IOHDRSZ > conn->msize) { np_werror(Etoolarge, EIO); goto error; } rc = (*conn->srv->write)(fid, tc->offset, tc->count, tc->data, req); if (rc || np_haserror()) np_fid_decref(fid); return rc; error: np_fid_decref(fid); return NULL; }
static Npfcall * np_create(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (fid->omode != (u16)~0) { np_werror(Ebadusefid, EIO); goto done; } if (!fid->type&Qtdir) { np_werror(Enotdir, ENOTDIR); goto done; } if (tc->perm&Dmdir && tc->mode!=Oread) { np_werror(Eperm, EPERM); goto done; } if (tc->perm&(Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice|Dmsocket) && !fid->conn->dotu) { np_werror(Eperm, EPERM); goto done; } rc = (*conn->srv->create)(fid, &tc->name, tc->perm, tc->mode, &tc->extension); if (rc && rc->id == Rcreate) { fid->omode = tc->mode; fid->type = rc->qid.type; } done: np_fid_decref(fid); return rc; }
/* Tattach - attach a new user (fid->user) to aname. * diod_auth.c::diod_checkauth first authenticates/authorizes user */ Npfcall* diod_attach (Npfid *fid, Npfid *afid, Npstr *aname) { Npfcall* ret = NULL; Fid *f = NULL; Npqid qid; struct stat sb; if (aname->len == 0 || *aname->str != '/') { np_uerror (EPERM); goto error; } if (!(f = _fidalloc ()) || !(f->path = np_strdup (aname))) { np_uerror (ENOMEM); goto error; } if (diod_conf_opt_runasuid ()) { if (fid->user->uid != diod_conf_get_runasuid ()) { np_uerror (EPERM); goto error; } } if (!diod_match_exports (f->path, fid->conn, fid->user, &f->xflags)) goto error; if (stat (f->path, &sb) < 0) { /* OK to follow symbolic links */ np_uerror (errno); goto error; } if (!S_ISDIR (sb.st_mode)) { np_uerror (ENOTDIR); goto error; } _ustat2qid (&sb, &qid); if ((ret = np_create_rattach (&qid)) == NULL) { np_uerror (ENOMEM); goto error; } fid->aux = f; np_fid_incref (fid); return ret; error: errn (np_rerror (), "diod_attach %s@%s:%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), aname->len, aname->str); if (f) _fidfree (f); return NULL; }
static Npfcall * np_remove(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; rc = (*conn->srv->remove)(fid); done: np_fid_decref(fid); return rc; }
static Npfcall * np_clunk(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; rc = NULL; conn = req->conn; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (fid->type&Qtauth) { if (conn->srv->auth) rc = conn->srv->auth->clunk(fid); else np_werror(Ebadusefid, EIO); goto done; } if (fid->omode!=(u16)~0 && fid->omode==Orclose) { rc = (*conn->srv->remove)(fid); if (rc->id == Rerror) goto done; free(rc); rc = np_create_rclunk(); } else rc = (*conn->srv->clunk)(fid); done: np_fid_decref(fid); return rc; }
static Npfcall * np_wstat(Npreq *req, Npfcall *tc) { Npconn *conn; Npfid *fid; Npfcall *rc; Npstat *stat; rc = NULL; conn = req->conn; stat = &tc->stat; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (stat->type != (u16)~0 || stat->dev != (u32)~0 || stat->qid.version != (u32)~0 || stat->qid.path != (u64)~0 ) { np_werror(Eperm, EPERM); goto done; } if ((fid->type&Qtdir && !stat->mode&Dmdir) || (!fid->type&Qtdir&&stat->mode&Dmdir)) { np_werror(Edirchange, EPERM); goto done; } rc = (*conn->srv->wstat)(fid, &tc->stat); done: np_fid_decref(fid); return rc; }
Npfcall * np_walk(Npreq *req, Npfcall *tc) { int i; Npconn *conn = req->conn; Npfid *fid = req->fid; Npfid *newfid = NULL; Npfcall *rc = NULL; Npqid wqids[P9_MAXWELEM]; if (!fid) { np_uerror (EIO); goto done; } #if 0 if (!(fid->type & P9_QTDIR)) { np_uerror(ENOTDIR); goto done; } #endif /* FIXME: error if fid has been opened */ if (tc->u.twalk.nwname > P9_MAXWELEM) { np_uerror(EIO); goto done; } if (tc->u.twalk.fid != tc->u.twalk.newfid) { newfid = np_fid_find(conn, tc->u.twalk.newfid); if (newfid) { np_uerror(EIO); goto done; } newfid = np_fid_create(conn, tc->u.twalk.newfid, NULL); if (!newfid) goto done; if (fid->type & P9_QTTMP) { if (!np_ctl_clone (fid, newfid)) goto done; } else { if (!conn->srv->clone) goto done; if (!(*conn->srv->clone)(fid, newfid)) goto done; } np_user_incref(fid->user); newfid->user = fid->user; np_tpool_incref(fid->tpool); newfid->tpool = fid->tpool; newfid->type = fid->type; if (!(newfid->aname = strdup (fid->aname))) { np_uerror (ENOMEM); goto done; } } else newfid = fid; np_fid_incref(newfid); if (!(newfid->type & P9_QTTMP)) { if (np_setfsid (req, newfid->user, -1) < 0) goto done; } for(i = 0; i < tc->u.twalk.nwname;) { if (newfid->type & P9_QTTMP) { if (!np_ctl_walk (newfid, &tc->u.twalk.wnames[i], &wqids[i])) break; } else { if (!conn->srv->walk) { np_uerror (ENOSYS); break; } if (!(*conn->srv->walk)(newfid, &tc->u.twalk.wnames[i], &wqids[i])) break; } newfid->type = wqids[i].type; i++; if (i<(tc->u.twalk.nwname) && !(newfid->type & P9_QTDIR)) break; } if (i==0 && tc->u.twalk.nwname!=0) goto done; np_uerror(0); if (tc->u.twalk.fid != tc->u.twalk.newfid) np_fid_incref(newfid); rc = np_create_rwalk(i, wqids); done: np_fid_decref(newfid); return rc; }
/* Look up operation's fid and assign it to req->fid. * This is done before the request is handed off to a worker, with * the plan of using fid data in scheduling work. * The fid refcount is incremented here, then decremented in np_respond (). */ static void np_preprocess_request(Npreq *req) { Npfcall *tc = req->tcall; Npconn *conn = req->conn; switch (tc->type) { case P9_TSTATFS: req->fid = np_fid_find (conn, tc->u.tstatfs.fid); break; case P9_TLOPEN: req->fid = np_fid_find (conn, tc->u.tlopen.fid); break; case P9_TLCREATE: req->fid = np_fid_find (conn, tc->u.tlcreate.fid); break; case P9_TSYMLINK: req->fid = np_fid_find (conn, tc->u.tsymlink.fid); break; case P9_TMKNOD: req->fid = np_fid_find (conn, tc->u.tmknod.fid); break; case P9_TRENAME: req->fid = np_fid_find (conn, tc->u.trename.fid); break; case P9_TREADLINK: req->fid = np_fid_find (conn, tc->u.treadlink.fid); break; case P9_TGETATTR: req->fid = np_fid_find (conn, tc->u.tgetattr.fid); break; case P9_TSETATTR: req->fid = np_fid_find (conn, tc->u.tsetattr.fid); break; case P9_TXATTRWALK: req->fid = np_fid_find (conn, tc->u.txattrwalk.fid); break; case P9_TXATTRCREATE: req->fid = np_fid_find (conn, tc->u.txattrcreate.fid); break; case P9_TREADDIR: req->fid = np_fid_find (conn, tc->u.treaddir.fid); break; case P9_TFSYNC: req->fid = np_fid_find (conn, tc->u.tfsync.fid); break; case P9_TLOCK: req->fid = np_fid_find (conn, tc->u.tlock.fid); break; case P9_TGETLOCK: req->fid = np_fid_find (conn, tc->u.tgetlock.fid); break; case P9_TLINK: req->fid = np_fid_find (conn, tc->u.tlink.dfid); break; case P9_TMKDIR: req->fid = np_fid_find (conn, tc->u.tmkdir.fid); break; case P9_TVERSION: break; case P9_TAUTH: if (np_fid_find (conn, tc->u.tauth.afid)) break; req->fid = np_fid_create (conn, tc->u.tauth.afid, NULL); if (!req->fid) break; req->fid->aname = np_strdup (&tc->u.tauth.aname); if (!req->fid->aname) { np_fid_destroy(req->fid); req->fid = NULL; } /* XXX leave fid->tpool NULL for now as auth * can be handled in the default thread pool * without risk of deadlock. */ break; case P9_TATTACH: if (np_fid_find (conn, tc->u.tattach.fid)) break; req->fid = np_fid_create (conn, tc->u.tattach.fid,NULL); if (!req->fid) break; req->fid->aname = np_strdup (&tc->u.tattach.aname); if (!req->fid->aname) { np_fid_destroy(req->fid); req->fid = NULL; } np_tpool_select (req); break; case P9_TFLUSH: break; case P9_TWALK: req->fid = np_fid_find (conn, tc->u.twalk.fid); break; case P9_TREAD: req->fid = np_fid_find (conn, tc->u.tread.fid); break; case P9_TWRITE: req->fid = np_fid_find (conn, tc->u.twrite.fid); break; case P9_TCLUNK: req->fid = np_fid_find (conn, tc->u.tclunk.fid); break; case P9_TREMOVE: req->fid = np_fid_find (conn, tc->u.tremove.fid); break; default: break; } if (req->fid) np_fid_incref (req->fid); }
static Npfcall * np_walk(Npreq *req, Npfcall *tc) { int i; Npconn *conn; Npfid *fid, *newfid; Npfcall *rc; Npqid wqids[MAXWELEM]; rc = NULL; conn = req->conn; newfid = NULL; fid = np_fid_find(conn, tc->fid); if (!fid) { np_werror(Eunknownfid, EIO); goto done; } else np_fid_incref(fid); req->fid = fid; if (!fid->type&Qtdir) { np_werror(Enotdir, ENOTDIR); goto done; } if (fid->omode != (u16) ~0) { np_werror(Ebadusefid, EIO); goto done; } if (tc->nwname > MAXWELEM) { np_werror(Etoomanywnames, EIO); goto done; } if (tc->fid != tc->newfid) { newfid = np_fid_find(conn, tc->newfid); if (newfid) { np_werror(Einuse, EIO); goto done; } newfid = np_fid_create(conn, tc->newfid, NULL); if (!newfid) { np_werror(Enomem, ENOMEM); goto done; } if (!(*conn->srv->clone)(fid, newfid)) goto done; newfid->user = fid->user; newfid->type = fid->type; } else newfid = fid; np_fid_incref(newfid); for(i = 0; i < tc->nwname;) { if (!(*conn->srv->walk)(newfid, &tc->wnames[i], &wqids[i])) break; newfid->type = wqids[i].type; i++; if (i<(tc->nwname) && !newfid->type&Qtdir) break; } if (i==0 && tc->nwname!=0) goto done; np_werror(NULL, 0); if (tc->fid != tc->newfid) np_fid_incref(newfid); rc = np_create_rwalk(i, wqids); done: np_fid_decref(fid); np_fid_decref(newfid); return rc; }
Npfcall * np_attach(Npreq *req, Npfcall *tc) { Npconn *conn = req->conn; Npsrv *srv = conn->srv; Npfid *fid = req->fid; Npfid *afid = NULL; Npfcall *rc = NULL; char a[128]; int auth_required = _authrequired(srv, &tc->u.tattach.uname, tc->u.tattach.n_uname, &tc->u.tattach.aname); if (tc->u.tattach.n_uname != P9_NONUNAME) { snprintf (a, sizeof(a), "attach(%d@%s:%.*s)", tc->u.tattach.n_uname, np_conn_get_client_id (conn), tc->u.tattach.aname.len, tc->u.tattach.aname.str); } else { snprintf (a, sizeof(a), "attach(%.*s@%s:%.*s)", tc->u.tattach.uname.len, tc->u.tattach.uname.str, np_conn_get_client_id (conn), tc->u.tattach.aname.len, tc->u.tattach.aname.str); } if (!fid) { np_uerror (EIO); np_logerr (srv, "%s: invalid fid (%d)", a, tc->u.tattach.fid); goto error; } if (tc->u.tattach.afid != P9_NOFID) { if (!(afid = np_fid_find(conn, tc->u.tattach.afid))) { np_uerror(EPERM); np_logerr (srv, "%s: invalid afid (%d)", a, tc->u.tattach.afid); goto error; } np_fid_incref(afid); if (!(afid->type & P9_QTAUTH)) { np_uerror(EPERM); np_logerr (srv, "%s: invalid afid type", a); goto error; } } if (auth_required) { if (afid) { fid->user = np_afid2user (afid, &tc->u.tattach.uname, tc->u.tattach.n_uname); if (!fid->user) { np_logerr (srv, "%s: invalid afid user", a); goto error; } if (srv->auth->checkauth(fid, afid, fid->aname) == 0) { np_logerr (srv, "%s: checkauth", a); goto error; } np_conn_set_authuser(conn, fid->user->uid); } else { u32 uid; fid->user = np_attach2user (srv, &tc->u.tattach.uname, tc->u.tattach.n_uname); if (!fid->user) { np_logerr (srv, "%s: user lookup", a); goto error; } if (!(srv->flags & SRV_FLAGS_AUTHCONN)) { np_uerror(EPERM); np_logerr (srv, "%s: auth required", a); goto error; } if (np_conn_get_authuser(conn, &uid) < 0) { np_uerror(EPERM); np_logerr (srv, "%s: prior auth required", a); goto error; } if (uid != 0 && uid != fid->user->uid) { np_uerror(EPERM); np_logerr (srv, "%s: insufficient auth", a); goto error; } } } if (srv->remapuser) { /* squash user handling */ if (srv->remapuser(fid, &tc->u.tattach.uname, tc->u.tattach.n_uname, &tc->u.tattach.aname) < 0) { np_logerr (srv, "%s: error remapping user", a); goto error; } } if (!fid->user) { fid->user = np_attach2user (srv, &tc->u.tattach.uname, tc->u.tattach.n_uname); if (!fid->user) { np_logerr (srv, "%s: user lookup", a); goto error; } } if (!strcmp (fid->aname, "ctl")) { rc = np_ctl_attach (fid, afid, fid->aname); } else { if (!srv->attach) { np_uerror (EIO); goto error; } rc = (*srv->attach)(fid, afid, &tc->u.tattach.aname); } error: if (afid) np_fid_decref(afid); return rc; }