/*
* 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 <u.h>
#include <libc.h>
#include <thread.h>
#include <fcall.h>
#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);
}
|