/* $Id: getfh3.C,v 1.7 2001/10/08 22:40:14 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "arpc.h" #include "getfh3.h" #include "sfsmisc.h" #include "rxx.h" static AUTH *auth_root = authunixint_create (myname () ? myname ().cstr () : "localhost", 0, 0, 0, NULL); const strbuf & strbuf_cat (const strbuf &sb, mountstat3 stat) { switch (stat) { case MNT3_OK: return strbuf_cat (sb, "no error", false); case MNT3ERR_PERM: return strbuf_cat (sb, "Not owner", false); case MNT3ERR_NOENT: return strbuf_cat (sb, "No such file or directory", false); case MNT3ERR_IO: return strbuf_cat (sb, "I/O error", false); case MNT3ERR_ACCES: return strbuf_cat (sb, "Permission denied", false); case MNT3ERR_NOTDIR: return strbuf_cat (sb, "Not a directory", false); case MNT3ERR_INVAL: return strbuf_cat (sb, "Invalid argument", false); case MNT3ERR_NAMETOOLONG: return strbuf_cat (sb, "Filename too long", false); case MNT3ERR_NOTSUPP: return strbuf_cat (sb, "Operation not supported", false); case MNT3ERR_SERVERFAULT: return strbuf_cat (sb, "Server failure", false); } return sb << "Unknown error " << int (stat); } template inline str stat2str (T xstat, clnt_stat stat) { if (stat) return strbuf () << stat; else if (xstat) return strbuf () << xstat; else return NULL; } static void splitpath (vec &out, str in) { const char *p = in.cstr (); const char *e = p + in.len (); const char *n; for (;;) { while (*p == '/') p++; for (n = p; n < e && *n != '/'; n++) ; if (n == p) return; out.push_back (str (p, n - p)); p = n; } } struct lookup3obj { typedef callback::ref cb_t; ref c; vec cns; cb_t cb; lookup3res res; getattr3res ares; AUTH *auth; void getattr (clnt_stat stat) { if (stat || ares.status) (*cb) (NULL, NULL, stat2str (ares.status, stat)); else { stompcast (ares); (*cb) (&res.resok->object, ares.attributes.addr (), NULL); } delete this; } void nextcn (const nfs_fh3 &fh, const fattr3exp *attrp) { if (!cns.size ()) { if (attrp) { (*cb) (&fh, attrp, NULL); delete this; } else c->call (NFSPROC3_GETATTR, &fh, &ares, wrap (this, &lookup3obj::getattr), auth); return; } diropargs3 arg; arg.dir = fh; arg.name = cns.pop_front (); c->call (NFSPROC3_LOOKUP, &arg, &res, wrap (this, &lookup3obj::getres), auth); } void getres (clnt_stat stat) { if (stat || res.status) { (*cb) (NULL, NULL, stat2str (res.status, stat)); delete this; } else { stompcast (res); nextcn (res.resok->object, res.resok->obj_attributes.present ? res.resok->obj_attributes.attributes : static_cast (NULL)); } } lookup3obj (ref c, const nfs_fh3 &start, str path, cb_t cb, const authunix_parms *aup) : c (c), cb (cb) { if (aup) { auth = authopaque_create (); authopaque_set (auth, aup); } else auth = auth_root; splitpath (cns, path); res.resok->object = start; nextcn (start, NULL); } ~lookup3obj () { if (auth != auth_root) AUTH_DESTROY (auth); } }; void lookupfh3 (ref c, const nfs_fh3 &start, str path, lookup3obj::cb_t cb, const authunix_parms *aup) { vNew lookup3obj (c, start, path, cb, aup); } static rxx stripslash ("^(.*[^/]+)/+$"); static rxx dirbaserx ("^((/+[^/]+)*)/+([^/]+)$"); struct getfh3obj { typedef callback::ref cb_t; cb_t cb; ptr c; str mountpath; str lookuppath; mountres3 res; mountstat3 firsterr; str host; void fail (clnt_stat stat) { (*cb) (NULL, strbuf () << stat); delete this; } void fail (mountstat3 stat) { (*cb) (NULL, strbuf () << stat); delete this; } void lookupcb (const nfs_fh3 *fhp, const fattr3exp *, str err) { if (err) /* Note, err may be more descriptive than firsterr, but it will * also be confusing. For example, suppose / is exported, /usr * is an unexported file system, and we are trying to get the * handle for /usr/local. firsterr will be permission denied, * while err will say no such file or directory. */ fail (firsterr); else { (*cb) (fhp, NULL); delete this; } } void gotnfsc (ptr nfsc, clnt_stat stat) { if (stat) fail (stat); else { nfs_fh3 fh; fh.data = res.mountinfo->fhandle; lookupfh3 (nfsc, fh, lookuppath, wrap (this, &getfh3obj::lookupcb)); } } void gotfh3 (clnt_stat stat) { if (stat) fail (stat); else if (res.fhs_status) { if (!firsterr) firsterr = res.fhs_status; if (stripslash.match (mountpath)) mountpath = stripslash[1]; else if (dirbaserx.match (mountpath) && host) { if (lookuppath) lookuppath = dirbaserx[3] << "/" << lookuppath; else lookuppath = dirbaserx[3]; mountpath = dirbaserx[1]; if (!mountpath.len ()) mountpath = "/"; } else { fail (firsterr); return; } domount (); } else { nfs_fh3 fh; fh.data = res.mountinfo->fhandle; if (lookuppath) aclntudp_create (host, 0, nfs_program_3, wrap (this, &getfh3obj::gotnfsc)); else { (*cb) (&fh, NULL); delete this; } } } void domount () { c->call (MOUNTPROC3_MNT, &mountpath, &res, wrap (this, &getfh3obj::gotfh3), auth_root); } void gotc (ptr cc, clnt_stat stat) { c = cc; if (stat) fail (stat); else domount (); } getfh3obj (str host, dirpath path, cb_t cb) : cb (cb), mountpath (path), firsterr (MNT3_OK), host (host) { aclntudp_create (host, 0, mount_program_3, wrap (this, &getfh3obj::gotc)); } getfh3obj (ref cc, dirpath path, cb_t cb) : cb (cb), c (cc), mountpath (path), firsterr (MNT3_OK) { domount (); } }; void getfh3 (str host, const str path, getfh3obj::cb_t cb) { vNew getfh3obj (host, path, cb); } void getfh3 (ref c, const str path, getfh3obj::cb_t cb) { vNew getfh3obj (c, path, cb); }