1implement Fsys; 2 3include "common.m"; 4 5sys : Sys; 6styx : Styx; 7styxaux : Styxaux; 8acme : Acme; 9dat : Dat; 10utils : Utils; 11look : Look; 12windowm : Windowm; 13xfidm : Xfidm; 14 15QTDIR, QTFILE, QTAPPEND : import Sys; 16DMDIR, DMAPPEND, Qid, ORCLOSE, OTRUNC, OREAD, OWRITE, ORDWR, Dir : import Sys; 17sprint : import sys; 18MAXWELEM, Rerror : import Styx; 19Qdir,Qacme,Qcons,Qconsctl,Qdraw,Qeditout,Qindex,Qlabel,Qnew,QWaddr,QWbody,QWconsctl,QWctl,QWdata,QWeditout,QWevent,QWrdsel,QWwrsel,QWtag,QMAX : import Dat; 20TRUE, FALSE : import Dat; 21cxfidalloc, cerr : import dat; 22Mntdir, Fid, Dirtab, Lock, Ref, Smsg0 : import dat; 23Tmsg, Rmsg : import styx; 24msize, version, fid, uname, aname, newfid, name, mode, offset, count, setmode : import styxaux; 25Xfid : import xfidm; 26row : import dat; 27Column : import Columnm; 28Window : import windowm; 29lookid : import look; 30warning, error : import utils; 31 32init(mods : ref Dat->Mods) 33{ 34 messagesize = Styx->MAXRPC; 35 36 sys = mods.sys; 37 styx = mods.styx; 38 styxaux = mods.styxaux; 39 acme = mods.acme; 40 dat = mods.dat; 41 utils = mods.utils; 42 look = mods.look; 43 windowm = mods.windowm; 44 xfidm = mods.xfidm; 45} 46 47sfd, cfd : ref Sys->FD; 48 49Nhash : con 16; 50DEBUG : con 0; 51 52fids := array[Nhash] of ref Fid; 53 54Eperm := "permission denied"; 55Eexist := "file does not exist"; 56Enotdir := "not a directory"; 57 58dirtab := array[10] of { 59 Dirtab ( ".", QTDIR, Qdir, 8r500|DMDIR ), 60 Dirtab ( "acme", QTDIR, Qacme, 8r500|DMDIR ), 61 Dirtab ( "cons", QTFILE, Qcons, 8r600 ), 62 Dirtab ( "consctl", QTFILE, Qconsctl, 8r000 ), 63 Dirtab ( "draw", QTDIR, Qdraw, 8r000|DMDIR ), 64 Dirtab ( "editout", QTFILE, Qeditout, 8r200 ), 65 Dirtab ( "index", QTFILE, Qindex, 8r400 ), 66 Dirtab ( "label", QTFILE, Qlabel, 8r600 ), 67 Dirtab ( "new", QTDIR, Qnew, 8r500|DMDIR ), 68 Dirtab ( nil, 0, 0, 0 ), 69}; 70 71dirtabw := array[12] of { 72 Dirtab ( ".", QTDIR, Qdir, 8r500|DMDIR ), 73 Dirtab ( "addr", QTFILE, QWaddr, 8r600 ), 74 Dirtab ( "body", QTAPPEND, QWbody, 8r600|DMAPPEND ), 75 Dirtab ( "ctl", QTFILE, QWctl, 8r600 ), 76 Dirtab ( "consctl", QTFILE, QWconsctl, 8r200 ), 77 Dirtab ( "data", QTFILE, QWdata, 8r600 ), 78 Dirtab ( "editout", QTFILE, QWeditout, 8r200 ), 79 Dirtab ( "event", QTFILE, QWevent, 8r600 ), 80 Dirtab ( "rdsel", QTFILE, QWrdsel, 8r400 ), 81 Dirtab ( "wrsel", QTFILE, QWwrsel, 8r200 ), 82 Dirtab ( "tag", QTAPPEND, QWtag, 8r600|DMAPPEND ), 83 Dirtab ( nil, 0, 0, 0 ), 84}; 85 86Mnt : adt { 87 qlock : ref Lock; 88 id : int; 89 md : ref Mntdir; 90}; 91 92mnt : Mnt; 93user : string; 94clockfd : ref Sys->FD; 95closing := 0; 96 97fsysinit() 98{ 99 p : array of ref Sys->FD; 100 101 p = array[2] of ref Sys->FD; 102 if(sys->pipe(p) < 0) 103 error("can't create pipe"); 104 cfd = p[0]; 105 sfd = p[1]; 106 clockfd = sys->open("/dev/time", Sys->OREAD); 107 user = utils->getuser(); 108 if (user == nil) 109 user = "Wile. E. Coyote"; 110 mnt.qlock = Lock.init(); 111 mnt.id = 0; 112 spawn fsysproc(); 113} 114 115fsyscfd() : int 116{ 117 return cfd.fd; 118} 119 120QID(w, q : int) : int 121{ 122 return (w<<8)|q; 123} 124 125FILE(q : Qid) : int 126{ 127 return int q.path & 16rFF; 128} 129 130WIN(q : Qid) : int 131{ 132 return (int q.path>>8) & 16rFFFFFF; 133} 134 135# nullsmsg : Smsg; 136nullsmsg0 : Smsg0; 137 138fsysproc() 139{ 140 n, ok : int; 141 x : ref Xfid; 142 f : ref Fid; 143 t : Smsg0; 144 145 acme->fsyspid = sys->pctl(0, nil); 146 x = nil; 147 for(;;){ 148 if(x == nil){ 149 cxfidalloc <-= nil; 150 x = <-cxfidalloc; 151 } 152 n = sys->read(sfd, x.buf, messagesize); 153 if(n <= 0) { 154 if (closing) 155 break; 156 error("i/o error on server channel"); 157 } 158 (ok, x.fcall) = Tmsg.unpack(x.buf[0:n]); 159 if(ok < 0) 160 error("convert error in convM2S"); 161 if(DEBUG) 162 utils->debug(sprint("%d:%s\n", x.tid, x.fcall.text())); 163 pick fc := x.fcall { 164 Version => 165 f = nil; 166 Auth => 167 f = nil; 168 * => 169 f = allocfid(fid(x.fcall)); 170 } 171 x.f = f; 172 pick fc := x.fcall { 173 Readerror => x = fsyserror(); 174 Flush => x = fsysflush(x); 175 Version => x = fsysversion(x); 176 Auth => x = fsysauth(x); 177 Attach => x = fsysattach(x, f); 178 Walk => x = fsyswalk(x, f); 179 Open => x = fsysopen(x, f); 180 Create => x = fsyscreate(x); 181 Read => x = fsysread(x, f); 182 Write => x = fsyswrite(x); 183 Clunk => x = fsysclunk(x, f); 184 Remove => x = fsysremove(x); 185 Stat => x = fsysstat(x, f); 186 Wstat => x = fsyswstat(x); 187 # Clone => x = fsysclone(x, f); 188 * => 189 x = respond(x, t, "bad fcall type"); 190 } 191 } 192} 193 194fsysaddid(dir : string, ndir : int, incl : array of string, nincl : int) : ref Mntdir 195{ 196 m : ref Mntdir; 197 id : int; 198 199 mnt.qlock.lock(); 200 id = ++mnt.id; 201 m = ref Mntdir; 202 m.id = id; 203 m.dir = dir; 204 m.refs = 1; # one for Command, one will be incremented in attach 205 m.ndir = ndir; 206 m.next = mnt.md; 207 m.incl = incl; 208 m.nincl = nincl; 209 mnt.md = m; 210 mnt.qlock.unlock(); 211 return m; 212} 213 214fsysdelid(idm : ref Mntdir) 215{ 216 m, prev : ref Mntdir; 217 i : int; 218 219 if(idm == nil) 220 return; 221 mnt.qlock.lock(); 222 if(--idm.refs > 0){ 223 mnt.qlock.unlock(); 224 return; 225 } 226 prev = nil; 227 for(m=mnt.md; m != nil; m=m.next){ 228 if(m == idm){ 229 if(prev != nil) 230 prev.next = m.next; 231 else 232 mnt.md = m.next; 233 for(i=0; i<m.nincl; i++) 234 m.incl[i] = nil; 235 m.incl = nil; 236 m.dir = nil; 237 m = nil; 238 mnt.qlock.unlock(); 239 return; 240 } 241 prev = m; 242 } 243 mnt.qlock.unlock(); 244 buf := sys->sprint("fsysdelid: can't find id %d\n", idm.id); 245 cerr <-= buf; 246} 247 248# 249# Called only in exec.l:run(), from a different FD group 250# 251fsysmount(dir : string, ndir : int, incl : array of string, nincl : int) : ref Mntdir 252{ 253 m : ref Mntdir; 254 255 # close server side so don't hang if acme is half-exited 256 # sfd = nil; 257 m = fsysaddid(dir, ndir, incl, nincl); 258 buf := sys->sprint("%d", m.id); 259 if(sys->mount(cfd, nil, "/mnt/acme", Sys->MREPL, buf) < 0){ 260 fsysdelid(m); 261 return nil; 262 } 263 # cfd = nil; 264 sys->bind("/mnt/acme", "/chan", Sys->MBEFORE); # was MREPL 265 if(sys->bind("/mnt/acme", "/dev", Sys->MBEFORE) < 0){ 266 fsysdelid(m); 267 return nil; 268 } 269 return m; 270} 271 272fsysclose() 273{ 274 closing = 1; 275 # sfd = cfd = nil; 276} 277 278respond(x : ref Xfid, t0 : Smsg0, err : string) : ref Xfid 279{ 280 t : ref Rmsg; 281 282 # t = nullsmsg; 283 tag := x.fcall.tag; 284 # fid := fid(x.fcall); 285 qid := t0.qid; 286 if(err != nil) 287 t = ref Rmsg.Error(tag, err); 288 else 289 pick fc := x.fcall { 290 Readerror => t = ref Rmsg.Error(tag, err); 291 Flush => t = ref Rmsg.Flush(tag); 292 Version => t = ref Rmsg.Version(tag, t0.msize, t0.version); 293 Auth => t = ref Rmsg.Auth(tag, qid); 294 # Clone => t = ref Rmsg.Clone(tag, fid); 295 Attach => t = ref Rmsg.Attach(tag, qid); 296 Walk => t = ref Rmsg.Walk(tag, t0.qids); 297 Open => t = ref Rmsg.Open(tag, qid, t0.iounit); 298 Create => t = ref Rmsg.Create(tag, qid, 0); 299 Read => if(t0.count == len t0.data) 300 t = ref Rmsg.Read(tag, t0.data); 301 else 302 t = ref Rmsg.Read(tag, t0.data[0: t0.count]); 303 Write => t = ref Rmsg.Write(tag, t0.count); 304 Clunk => t = ref Rmsg.Clunk(tag); 305 Remove => t = ref Rmsg.Remove(tag); 306 Stat => t = ref Rmsg.Stat(tag, t0.stat); 307 Wstat => t = ref Rmsg.Wstat(tag); 308 309 } 310 # t.qid = t0.qid; 311 # t.count = t0.count; 312 # t.data = t0.data; 313 # t.stat = t0.stat; 314 # t.fid = x.fcall.fid; 315 # t.tag = x.fcall.tag; 316 buf := t.pack(); 317 if(buf == nil) 318 error("convert error in convS2M"); 319 if(sys->write(sfd, buf, len buf) != len buf) 320 error("write error in respond"); 321 buf = nil; 322 if(DEBUG) 323 utils->debug(sprint("%d:r: %s\n", x.tid, t.text())); 324 return x; 325} 326 327# fsysnop(x : ref Xfid) : ref Xfid 328# { 329# t : Smsg0; 330# 331# return respond(x, t, nil); 332# } 333 334fsyserror() : ref Xfid 335{ 336 error("sys error : Terror"); 337 return nil; 338} 339 340fsyssession(x : ref Xfid) : ref Xfid 341{ 342 t : Smsg0; 343 344 # BUG: should shut everybody down ?? 345 t = nullsmsg0; 346 return respond(x, t, nil); 347} 348 349fsysversion(x : ref Xfid) : ref Xfid 350{ 351 t : Smsg0; 352 353 pick m := x.fcall { 354 Version => 355 (t.msize, t.version) = styx->compatible(m, messagesize, nil); 356 messagesize = t.msize; 357 return respond(x, t, nil); 358 } 359 return respond(x, t, "acme: bad version"); 360 361 # ms := msize(x.fcall); 362 # if(ms < 256) 363 # return respond(x, t, "version: message size too small"); 364 # t.msize = messagesize = ms; 365 # v := version(x.fcall); 366 # if(len v < 6 || v[0: 6] != "9P2000") 367 # return respond(x, t, "unrecognized 9P version"); 368 # t.version = "9P2000"; 369 # return respond(x, t, nil); 370} 371 372fsysauth(x : ref Xfid) : ref Xfid 373{ 374 t : Smsg0; 375 376 return respond(x, t, "acme: authentication not required"); 377} 378 379fsysflush(x : ref Xfid) : ref Xfid 380{ 381 x.c <-= Xfidm->Xflush; 382 return nil; 383} 384 385fsysattach(x : ref Xfid, f : ref Fid) : ref Xfid 386{ 387 t : Smsg0; 388 id : int; 389 m : ref Mntdir; 390 391 if (uname(x.fcall) != user) 392 return respond(x, t, Eperm); 393 f.busy = TRUE; 394 f.open = FALSE; 395 f.qid = (Qid)(big Qdir, 0, QTDIR); 396 f.dir = dirtab; 397 f.nrpart = 0; 398 f.w = nil; 399 t.qid = f.qid; 400 f.mntdir = nil; 401 id = int aname(x.fcall); 402 mnt.qlock.lock(); 403 for(m=mnt.md; m != nil; m=m.next) 404 if(m.id == id){ 405 f.mntdir = m; 406 m.refs++; 407 break; 408 } 409 if(m == nil) 410 cerr <-= "unknown id in attach"; 411 mnt.qlock.unlock(); 412 return respond(x, t, nil); 413} 414 415fsyswalk(x : ref Xfid, f : ref Fid) : ref Xfid 416{ 417 t : Smsg0; 418 c, i, j, id : int; 419 path, qtype : int; 420 d, dir : array of Dirtab; 421 w : ref Window; 422 nf : ref Fid; 423 424 if(f.open) 425 return respond(x, t, "walk of open file"); 426 if(fid(x.fcall) != newfid(x.fcall)){ 427 nf = allocfid(newfid(x.fcall)); 428 if(nf.busy) 429 return respond(x, t, "newfid already in use"); 430 nf.busy = TRUE; 431 nf.open = FALSE; 432 nf.mntdir = f.mntdir; 433 if(f.mntdir != nil) 434 f.mntdir.refs++; 435 nf.dir = f.dir; 436 nf.qid = f.qid; 437 nf.w = f.w; 438 nf.nrpart = 0; # not open, so must be zero 439 if(nf.w != nil) 440 nf.w.refx.inc(); 441 f = nf; # walk f 442 } 443 444 qtype = QTFILE; 445 wqids: list of Qid; 446 err := string nil; 447 id = WIN(f.qid); 448 q := f.qid; 449 names := styxaux->names(x.fcall); 450 nwname := len names; 451 452 if(nwname > 0){ 453 for(i = 0; i < nwname; i++){ 454 if((q.qtype & QTDIR) == 0){ 455 err = Enotdir; 456 break; 457 } 458 459 name := names[i]; 460 if(name == ".."){ 461 path = Qdir; 462 qtype = QTDIR; 463 id = 0; 464 if(w != nil){ 465 w.close(); 466 w = nil; 467 } 468 if(i == MAXWELEM){ 469 err = "name too long"; 470 break; 471 } 472 q.qtype = qtype; 473 q.vers = 0; 474 q.path = big QID(id, path); 475 wqids = q :: wqids; 476 continue; 477 } 478 479 # is it a numeric name? 480 regular := 0; 481 for(j=0; j < len name; j++) { 482 c = name[j]; 483 if(c<'0' || '9'<c) { 484 regular = 1; 485 break; 486 } 487 } 488 489 if (!regular) { 490 # yes: it's a directory 491 if(w != nil) # name has form 27/23; get out before losing w 492 break; 493 id = int name; 494 row.qlock.lock(); 495 w = lookid(id, FALSE); 496 if(w == nil){ 497 row.qlock.unlock(); 498 break; 499 } 500 w.refx.inc(); 501 path = Qdir; 502 qtype = QTDIR; 503 row.qlock.unlock(); 504 dir = dirtabw; 505 if(i == MAXWELEM){ 506 err = "name too long"; 507 break; 508 } 509 q.qtype = qtype; 510 q.vers = 0; 511 q.path = big QID(id, path); 512 wqids = q :: wqids; 513 continue; 514 } 515 else { 516 # if(FILE(f.qid) == Qacme) # empty directory 517 # break; 518 if(name == "new"){ 519 if(w != nil) 520 error("w set in walk to new"); 521 cw := chan of ref Window; 522 spawn x.walk(cw); 523 w = <- cw; 524 w.refx.inc(); 525 path = QID(w.id, Qdir); 526 qtype = QTDIR; 527 id = w.id; 528 dir = dirtabw; 529 # x.c <-= Xfidm->Xwalk; 530 if(i == MAXWELEM){ 531 err = "name too long"; 532 break; 533 } 534 q.qtype = qtype; 535 q.vers = 0; 536 q.path = big QID(id, path); 537 wqids = q :: wqids; 538 continue; 539 } 540 541 if(id == 0) 542 d = dirtab; 543 else 544 d = dirtabw; 545 k := 1; # skip '.' 546 found := 0; 547 for( ; d[k].name != nil; k++){ 548 if(name == d[k].name){ 549 path = d[k].qid; 550 qtype = d[k].qtype; 551 dir = d[k:]; 552 if(i == MAXWELEM){ 553 err = "name too long"; 554 break; 555 } 556 q.qtype = qtype; 557 q.vers = 0; 558 q.path = big QID(id, path); 559 wqids = q :: wqids; 560 found = 1; 561 break; 562 } 563 } 564 if(found) 565 continue; 566 break; # file not found 567 } 568 } 569 570 if(i == 0 && err == nil) 571 err = Eexist; 572 } 573 574 nwqid := len wqids; 575 if(nwqid > 0){ 576 t.qids = array[nwqid] of Qid; 577 for(i = nwqid-1; i >= 0; i--){ 578 t.qids[i] = hd wqids; 579 wqids = tl wqids; 580 } 581 } 582 if(err != nil || nwqid < nwname){ 583 if(nf != nil){ 584 nf.busy = FALSE; 585 fsysdelid(nf.mntdir); 586 } 587 } 588 else if(nwqid == nwname){ 589 if(w != nil){ 590 f.w = w; 591 w = nil; 592 } 593 if(dir != nil) 594 f.dir = dir; 595 f.qid = q; 596 } 597 598 if(w != nil) 599 w.close(); 600 601 return respond(x, t, err); 602} 603 604fsysopen(x : ref Xfid, f : ref Fid) : ref Xfid 605{ 606 t : Smsg0; 607 m : int; 608 609 # can't truncate anything, so just disregard 610 setmode(x.fcall, mode(x.fcall)&~OTRUNC); 611 # can't execute or remove anything 612 if(mode(x.fcall)&ORCLOSE) 613 return respond(x, t, Eperm); 614 case(mode(x.fcall)){ 615 OREAD => 616 m = 8r400; 617 OWRITE => 618 m = 8r200; 619 ORDWR => 620 m = 8r600; 621 * => 622 return respond(x, t, Eperm); 623 } 624 if(((f.dir[0].perm&~(DMDIR|DMAPPEND))&m) != m) 625 return respond(x, t, Eperm); 626 x.c <-= Xfidm->Xopen; 627 return nil; 628} 629 630fsyscreate(x : ref Xfid) : ref Xfid 631{ 632 t : Smsg0; 633 634 return respond(x, t, Eperm); 635} 636 637idcmp(a, b : int) : int 638{ 639 return a-b; 640} 641 642qsort(a : array of int, n : int) 643{ 644 i, j : int; 645 t : int; 646 647 while(n > 1) { 648 i = n>>1; 649 t = a[0]; a[0] = a[i]; a[i] = t; 650 i = 0; 651 j = n; 652 for(;;) { 653 do 654 i++; 655 while(i < n && idcmp(a[i], a[0]) < 0); 656 do 657 j--; 658 while(j > 0 && idcmp(a[j], a[0]) > 0); 659 if(j < i) 660 break; 661 t = a[i]; a[i] = a[j]; a[j] = t; 662 } 663 t = a[0]; a[0] = a[j]; a[j] = t; 664 n = n-j-1; 665 if(j >= n) { 666 qsort(a, j); 667 a = a[j+1:]; 668 } else { 669 qsort(a[j+1:], n); 670 n = j; 671 } 672 } 673} 674 675fsysread(x : ref Xfid, f : ref Fid) : ref Xfid 676{ 677 t : Smsg0; 678 b : array of byte; 679 i, id, n, o, e, j, k, nids : int; 680 ids : array of int; 681 d : array of Dirtab; 682 dt : Dirtab; 683 c : ref Column; 684 clock : int; 685 686 b = nil; 687 if(f.qid.qtype & QTDIR){ 688 # if(int offset(x.fcall) % DIRLEN) 689 # return respond(x, t, "illegal offset in directory"); 690 if(FILE(f.qid) == Qacme){ # empty dir 691 t.data = nil; 692 t.count = 0; 693 respond(x, t, nil); 694 return x; 695 } 696 o = int offset(x.fcall); 697 e = int offset(x.fcall)+count(x.fcall); 698 clock = getclock(); 699 b = array[messagesize] of byte; 700 id = WIN(f.qid); 701 n = 0; 702 if(id > 0) 703 d = dirtabw; 704 else 705 d = dirtab; 706 k = 1; # first entry is '.' 707 leng := 0; 708 for(i=0; d[k].name!=nil && i<e; i+=leng){ 709 bb := styx->packdir(dostat(WIN(x.f.qid), d[k], clock)); 710 leng = len bb; 711 for (kk := 0; kk < leng; kk++) 712 b[kk+n] = bb[kk]; 713 bb = nil; 714 if(leng <= Styx->BIT16SZ) 715 break; 716 if(i >= o) 717 n += leng; 718 k++; 719 } 720 if(id == 0){ 721 row.qlock.lock(); 722 nids = 0; 723 ids = nil; 724 for(j=0; j<row.ncol; j++){ 725 c = row.col[j]; 726 for(k=0; k<c.nw; k++){ 727 oids := ids; 728 ids = array[nids+1] of int; 729 ids[0:] = oids[0:nids]; 730 oids = nil; 731 ids[nids++] = c.w[k].id; 732 } 733 } 734 row.qlock.unlock(); 735 qsort(ids, nids); 736 j = 0; 737 for(; j<nids && i<e; i+=leng){ 738 k = ids[j]; 739 dt.name = sys->sprint("%d", k); 740 dt.qid = QID(k, 0); 741 dt.qtype = QTDIR; 742 dt.perm = DMDIR|8r700; 743 bb := styx->packdir(dostat(k, dt, clock)); 744 leng = len bb; 745 for (kk := 0; kk < leng; kk++) 746 b[kk+n] = bb[kk]; 747 bb = nil; 748 if(leng == 0) 749 break; 750 if(i >= o) 751 n += leng; 752 j++; 753 } 754 ids = nil; 755 } 756 t.data = b; 757 t.count = n; 758 respond(x, t, nil); 759 b = nil; 760 return x; 761 } 762 x.c <-= Xfidm->Xread; 763 return nil; 764} 765 766fsyswrite(x : ref Xfid) : ref Xfid 767{ 768 x.c <-= Xfidm->Xwrite; 769 return nil; 770} 771 772fsysclunk(x : ref Xfid, f : ref Fid) : ref Xfid 773{ 774 t : Smsg0; 775 776 fsysdelid(f.mntdir); 777 if(f.open){ 778 f.busy = FALSE; 779 f.open = FALSE; 780 x.c <-= Xfidm->Xclose; 781 return nil; 782 } 783 if(f.w != nil) 784 f.w.close(); 785 f.busy = FALSE; 786 f.open = FALSE; 787 return respond(x, t, nil); 788} 789 790fsysremove(x : ref Xfid) : ref Xfid 791{ 792 t : Smsg0; 793 794 return respond(x, t, Eperm); 795} 796 797fsysstat(x : ref Xfid, f : ref Fid) : ref Xfid 798{ 799 t : Smsg0; 800 801 t.stat = dostat(WIN(x.f.qid), f.dir[0], getclock()); 802 return respond(x, t, nil); 803} 804 805fsyswstat(x : ref Xfid) : ref Xfid 806{ 807 t : Smsg0; 808 809 return respond(x, t, Eperm); 810} 811 812allocfid(fid : int) : ref Fid 813{ 814 f, ff : ref Fid; 815 fh : int; 816 817 ff = nil; 818 fh = fid&(Nhash-1); 819 for(f=fids[fh]; f != nil; f=f.next) 820 if(f.fid == fid) 821 return f; 822 else if(ff==nil && f.busy==FALSE) 823 ff = f; 824 if(ff != nil){ 825 ff.fid = fid; 826 return ff; 827 } 828 f = ref Fid; 829 f.busy = FALSE; 830 f.rpart = array[Sys->UTFmax] of byte; 831 f.nrpart = 0; 832 f.fid = fid; 833 f.next = fids[fh]; 834 fids[fh] = f; 835 return f; 836} 837 838cbuf := array[32] of byte; 839 840getclock() : int 841{ 842 sys->seek(clockfd, big 0, 0); 843 n := sys->read(clockfd, cbuf, len cbuf); 844 return int string cbuf[0:n]; 845} 846 847dostat(id : int, dir : Dirtab, clock : int) : Sys->Dir 848{ 849 d : Dir; 850 851 d.qid.path = big QID(id, dir.qid); 852 d.qid.vers = 0; 853 d.qid.qtype = dir.qtype; 854 d.mode = dir.perm; 855 d.length = big 0; # would be nice to do better 856 d.name = dir.name; 857 d.uid = user; 858 d.gid = user; 859 d.atime = clock; 860 d.mtime = clock; 861 d.dtype = d.dev = 0; 862 return d; 863 # buf := styx->convD2M(d); 864 # d = nil; 865 # return buf; 866} 867