/* * Copyright (c) 2013, Coraid, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Coraid nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CORAID BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include <9p.h> #include "dat.h" /* * Version of pread that's careful to always work on sector boundaries */ long spread(int fd, void *a, long n, uvlong off) { char *buf; uvlong aoff, boff; long an, rn; boff = off % 512; if(n % 512 == 0 && boff == 0) return pread(fd, a, n, off); aoff = off & ~511; an = (n + boff + 511) & ~511; buf = θmalloc(an); rn = pread(fd, buf, an, aoff); if(rn <= 0) { free(buf); return rn; } rn -= boff; if(rn > n) rn = n; memmove(a, buf + boff, rn); free(buf); return rn; } long θpread(int fd, uvlong qpath, void *a, long n, uvlong off) { uvlong fblk, meta, now, len; ulong m, tot, boff; meta = q2m(fd, qpath, 0); if(meta == 0) return -1; if(getmetaint(fd, meta, "length", &len) == MTnone) len = 0; if(off >= len) n = 0; else if(off + n > len) n = len - off; tot = 0; while(n > 0) { fblk = locate(fd, meta, off / BlkSize, 0); boff = off % BlkSize; if(boff + n > BlkSize) m = BlkSize - boff; else m = n; if(fblk != 0) { if(fd == -1) m = cread((char *)a + tot, m, fblk * BlkSize + boff); else m = spread(fd, (char *)a + tot, m, fblk * BlkSize + boff); } else memset((char *)a + tot, 0, m); n -= m; off += m; tot += m; } if(fd == -1 && doatimes) { now = nsec(); setmetaint(meta, "atime", nil, now); } return tot; } long θpwrite(uvlong qpath, void *a, long n, uvlong off, int grow) { uvlong fblk, meta, woff, now, len, qvers; ulong m, tot, boff; meta = q2m(-1, qpath, 0); if(meta == 0) return -1; if(getmetaint(-1, meta, "length", &len) == MTnone) len = 0; if(grow == 0) { if(off >= len) n = 0; else if(off + n > len) n = len - off; } else if (grow == 2) off = len; woff = off; tot = 0; while(n > 0) { fblk = locate(-1, meta, woff / BlkSize, 1); if(fblk == 0) break; boff = woff % BlkSize; if(boff + n > BlkSize) m = BlkSize - boff; else m = n; m = cwrite((char *)a + tot, m, fblk * BlkSize + boff); woff += m; n -= m; tot += m; } if(grow) { if(off + tot > len) setmetaint(meta, "length", nil, off + tot); } now = nsec(); setmetaint(meta, "mtime", nil, now); setmetaint(meta, "atime", nil, now); if(getmetaint(-1, meta, "qvers", &qvers) != MTnone) qvers++; setmetaint(meta, "qvers", nil, qvers); return tot; } void rmdlist(uvlong meta, uvlong myqid) { uvlong sibqid, pqid, predqid; uvlong pmeta, qvers; getmetaint(-1, meta, "sib", &sibqid); getmetaint(-1, meta, "parent", &pqid); pmeta = q2m(-1, pqid, 0); if(pmeta == 0) { fprint(2, "warning: no parent?!?!\n"); return; } if(getmetaint(-1, pmeta, "qvers", &qvers) != MTnone) setmetaint(pmeta, "qvers", nil, qvers + 1); getmetaint(-1, pmeta, "child", &predqid); if(predqid == myqid) { setmetaint(pmeta, "child", nil, sibqid); return; } do { pmeta = q2m(-1, predqid, 0); if(pmeta == 0) return; getmetaint(-1, pmeta, "sib", &predqid); } while(predqid != myqid); setmetaint(pmeta, "sib", nil, sibqid); } void * θmalloc(ulong x) { if(x > 6553600) { fprint(2, "$%p", getcallerpc(&x)); return nil; } else return emalloc9p(x); }