📄 file.c
字号:
#include <u.h>#include <libc.h>#include "cformat.h"#include "lru.h"#include "bcache.h"#include "disk.h"#include "inode.h"#include "file.h"/* * merge data with that which already exists in a block * * we allow only one range per block, always use the new * data if the ranges don't overlap. */voidfmerge(Dptr *p, char *to, char *from, int start, int len){ int end; end = start + len; memmove(to+start, from, end-start); /* * if ranges do not overlap... */ if(start>p->end || p->start>end){ /* * just use the new data */ p->start = start; p->end = end; } else { /* * merge ranges */ if(start < p->start) p->start = start; if(end > p->end) p->end = end; }}/* * write a block (or less) of data onto a disk, follow it with any necessary * pointer writes. * * N.B. ordering is everything */intfbwrite(Icache *ic, Ibuf *b, char *a, ulong off, int len){ Bbuf *dbb; /* data block */ Bbuf *ibb; /* indirect block */ Dptr *p; Dptr t; ulong fbno; int wrinode; fbno = off / ic->bsize; p = &b->inode.ptr; ibb = 0; wrinode = 0; /* * are there any pages for this inode? */ if(p->bno == Notabno){ wrinode = 1; goto dowrite; } /* * is it an indirect block? */ if(p->bno & Indbno){ ibb = bcread(ic, p->bno); if(ibb == 0) return -1; p = (Dptr*)ibb->data; p += fbno % ic->p2b; goto dowrite; } /* * is it the wrong direct block? */ if((p->fbno%ic->p2b) != (fbno%ic->p2b)){ /* * yes, make an indirect block */ t = *p; dpalloc(ic, p); if(p->bno == Notabno){ *p = t; return -1; } ibb = bcalloc(ic, p->bno); if(ibb == 0){ *p = t; return -1; } p = (Dptr*)ibb->data; p += t.fbno % ic->p2b; *p = t; p = (Dptr*)ibb->data; p += fbno % ic->p2b; } wrinode = 1;dowrite: /* * get the data block into the block cache */ if(p->bno == Notabno){ /* * create a new block */ dalloc(ic, p); if(p->bno == Notabno) return -1; /* no blocks left (maybe) */ dbb = bcalloc(ic, p->bno); } else { /* * use what's there */ dbb = bcread(ic, p->bno); } if(dbb == 0) return -1; /* * merge in the new data */ if(p->fbno != fbno){ p->start = p->end = 0; p->fbno = fbno; } fmerge(p, dbb->data, a, off % ic->bsize, len); /* * write changed blocks back in the * correct order */ bcmark(ic, dbb); if(ibb){ bcmark(ic, ibb); } if(wrinode){ if(iwrite(ic, b) < 0) return -1; } return len;}/* * write `n' bytes to the cache * * return number of bytes written */longfwrite(Icache *ic, Ibuf *b, char *a, ulong off, long n){ int len; long sofar; for(sofar = 0; sofar < n; sofar += len){ len = ic->bsize - ((off+sofar)%ic->bsize); if(len > n - sofar) len = n - sofar; if(fbwrite(ic, b, a+sofar, off+sofar, len) < 0) return sofar; } return sofar;}/* * get a pointer to the next valid data at or after `off' */Dptr *fpget(Icache *ic, Ibuf *b, ulong off){ Bbuf *ibb; /* indirect block */ ulong fbno; long doff; Dptr *p; Dptr *p0; Dptr *pf; fbno = off / ic->bsize; p = &b->inode.ptr; /* * are there any pages for this inode? */ if(p->bno == Notabno) return 0; /* * if it's a direct block, life is easy? */ if(!(p->bno & Indbno)){ /* * a direct block, return p if it's at least past what we want */ if(p->fbno > fbno) return p; if(p->fbno < fbno) return 0; doff = off % ic->bsize; if(doff>=p->start && doff<p->end) return p; else return 0; } /* * read the indirect block */ ibb = bcread(ic, p->bno); if(ibb == 0) return 0; /* * find the next valid pointer */ p0 = (Dptr*)ibb->data; pf = p0 + (fbno % ic->p2b); if(pf->bno!=Notabno && pf->fbno==fbno){ doff = off % ic->bsize; if(doff<pf->end) return pf; } for(p = pf+1 ;p < p0 + ic->p2b; p++){ fbno++; if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end) return p; } for(p = p0 ;p < pf; p++){ fbno++; if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end) return p; } return 0;}/* * read `n' bytes from the cache. * * if we hit a gap and we've read something, * return number of bytes read so far. * * if we start with a gap, return minus the number of bytes * to the next data. * * if there are no bytes cached, return 0. */longfread(Icache *ic, Ibuf *b, char *a, ulong off, long n){ int len; Dptr *p; Bbuf *bb; long sofar; long gap; int start; for(sofar = 0; sofar < n; sofar += len, off += len){ /* * get pointer to next data */ len = n - sofar; p = fpget(ic, b, off); /* * if no more data, return what we have so far */ if(p == 0) return sofar; /* * if there's a gap, return the size of the gap */ gap = (ic->bsize*p->fbno + p->start) - off; if(gap>0){ if(sofar == 0) return -gap; else return sofar; } /* * return what we have */ bb = bcread(ic, p->bno); if(bb == 0) return sofar; start = p->start - gap; if(p->end - start < len) len = p->end - start; memmove(a + sofar, bb->data + start, len); } return sofar;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -