int kernel_unlink(char* path) { struct inode *ip, *dp; struct dirent de; char name[DIRSIZ]; uint off; // if(argstr(0, &path) < 0) // return -1; if((dp = nameiparent(path, name)) == 0) return -1; begin_trans(); ilock(dp); // Cannot unlink "." or "..". if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) goto bad; if((ip = dirlookup(dp, name, &off)) == 0) goto bad; ilock(ip); if(ip->nlink < 1) panic("unlink: nlink < 1"); /* if(ip->type == T_DIR && !isdirempty(ip)){ iunlockput(ip); goto bad; } */ memset(&de, 0, sizeof(de)); if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) panic("unlink: writei"); if(ip->type == T_DIR){ dp->nlink--; iupdate(dp); } iunlockput(dp); ip->nlink--; iupdate(ip); iunlockput(ip); commit_trans(); return 0; bad: iunlockput(dp); commit_trans(); return -1; }
// Write data to inode. int writei(struct inode *ip, char *src, uint off, uint n) { uint tot, m; struct buf *bp; char *addr; if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; return devsw[ip->major].write(ip, src, n); } if(off > ip->size || off + n < off) return -1; if(ip->type == T_SMALLFILE){ // handle T_SMALLFILE // cprintf("before n in readi : %d\t off = %d\t size = %d\n", n, off, ip->size); if(off + n > 52) n = 52 - off; addr = (char*)(ip->addrs); // get NDIRECT address memmove(addr + off, src, n); off += n; ip->size = off; iupdate(ip); return n; // cprintf("after n in readi : %d\t off = %d\t size = %d\n", n, off, ip->size); // cprintf("write addr: %s\n", *(addr + off)); } else { // handle T_FILE if(off + n > MAXFILE*BSIZE) n = MAXFILE*BSIZE - off; for(tot=0; tot<n; tot+=m, off+=m, src+=m){ uint sector_number = bmap(ip, off/BSIZE); if(sector_number == 0){ //failed to find block n = tot; //return number of bytes written so far break; } bp = bread(ip->dev, sector_number); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); bwrite(bp); brelse(bp); } } if(n > 0 && off > ip->size){ ip->size = off; iupdate(ip); // cprintf("last n in readi : %d\t off = %d\t size = %d\n", n, off, ip->size); } return n; }
// Truncate inode (discard contents). // Only called when the inode has no links // to it (no directory entries referring to it) // and has no in-memory reference to it (is // not an open file or current directory). static void itrunc(struct inode *ip) { int i, j; struct buf *bp; uint *a; for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } if(ip->addrs[NDIRECT]){ bp = bread(ip->dev, ip->addrs[NDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]) bfree(ip->dev, a[j]); } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT]); ip->addrs[NDIRECT] = 0; } ip->size = 0; iupdate(ip); }
/* * release an inode. * decrease the reference count, write updates to disk if nessary. * also check the link count, if zero, trucate it. * */ void iput(struct inode *ip){ ushort dev; if(ip==NULL) panic("bad struct inode*"); ip->i_flag |= I_LOCK; if (ip->i_count > 0) { ip->i_count--; } if (ip->i_count==0){ if (ip->i_nlink==0) { itrunc(ip); ifree(ip->i_dev, ip->i_num); } // if it's a device file, the dev number is stored in zone[0]. dev = ip->i_zone[0]; switch (ip->i_mode & S_IFMT) { case S_IFBLK: (*bdevsw[MAJOR(dev)].d_close)(dev); break; case S_IFCHR: (*cdevsw[MAJOR(dev)].d_close)(dev); break; } iupdate(ip); ip->i_flag = 0; ip->i_num = 0; } unlk_ino(ip); }
// PAGEBREAK! // Write data to inode. int writei(struct inode* ip, char* src, uint off, uint n) { // cprintf("writei \n"); uint tot, m; struct buf* bp; struct superblock sb; sb = sbs[ip->part->number]; if (ip->type == T_DEV) { if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; return devsw[ip->major].write(ip, src, n); } if (off > ip->size || off + n < off) return -1; if (off + n > MAXFILE * BSIZE) return -1; for (tot = 0; tot < n; tot += m, off += m, src += m) { uint bmapOut = bmap(ip, off / BSIZE); bp = bread(ip->dev, sb.offset + bmapOut); m = min(n - tot, BSIZE - off % BSIZE); memmove(bp->data + off % BSIZE, src, m); log_write(bp, ip->part->number); brelse(bp); } if (n > 0 && off > ip->size) { ip->size = off; iupdate(ip); } return n; }
// Truncate inode (discard contents). // Only called after the last dirent referring // to this inode has been erased on disk. static void itrunc(struct inode *ip) { int i, j; struct buf *bp; uint *a; if(ip->type != T_SMALLFILE) { // for all not small file, clear the blocks for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } if(ip->addrs[NDIRECT]){ bp = bread(ip->dev, ip->addrs[NDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]) bfree(ip->dev, a[j]); } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT]); ip->addrs[NDIRECT] = 0; } } ip->size = 0; iupdate(ip); }
/* truncate inode * only called when the inode has no links to it * and not any in-memory ref to it */ static void itrunc(struct inode *ip) { uint32_t i, j; struct buf *bp; uint16_t *zone2; /* free DIRECT block */ for (i = 0; i < NDIRECT; i++) { if (ip->zone[i]) { bfree(ip->dev, ip->zone[i]); ip->zone[i] = 0; } } /* free INDIRECT block */ if (ip->zone[NDIRECT]) { bp = bread(ip->dev,ip->zone[NDIRECT]); zone2 = (uint16_t *)bp->data; for (j = 0; j < NINDIRECT; j++) { if (zone2[j]) { bfree(ip->dev, zone2[j]); zone2[j] = 0; } } brelse(bp); bfree(ip->dev, ip->zone[NDIRECT]); ip->zone[NDIRECT] = 0; } /* DAUL INDIRECT block is unused*/ ip->size = 0; iupdate(ip); }
// PAGEBREAK! // Write data to inode. int writei(struct inode *ip, char *src, uint off, uint n) { uint tot, m; struct buf *bp; if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; //return 0; return devsw[ip->major].write(ip, src, n); } if(off > ip->size || off + n < off) return -1; if(off + n > MAXFILE*BSIZE) return -1; for(tot=0; tot<n; tot+=m, off+=m, src+=m){ bp = bread(ip->dev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); log_write(bp); brelse(bp); } if(n > 0 && off > ip->size){ ip->size = off; iupdate(ip); } return n; }
// Truncate inode (discard contents). // Only called when the inode has no links // to it (no directory entries referring to it) // and has no in-memory reference to it (is // not an open file or current directory). static void itrunc(struct inode* ip) { // cprintf("itrunc \n"); int i, j; struct buf* bp; uint* a; struct superblock sb; sb = sbs[ip->part->number]; for (i = 0; i < NDIRECT; i++) { if (ip->addrs[i]) { bfree(ip->dev, ip->addrs[i], ip->part->number); ip->addrs[i] = 0; } } if (ip->addrs[NDIRECT]) { bp = bread(ip->dev, sb.offset + ip->addrs[NDIRECT]); a = (uint*)bp->data; for (j = 0; j < NINDIRECT; j++) { if (a[j]) bfree(ip->dev, a[j], ip->part->number); } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT], ip->part->number); ip->addrs[NDIRECT] = 0; } ip->size = 0; iupdate(ip); }
// Truncate inode (discard contents). // Only called when the inode has no links // to it (no directory entries referring to it) // and has no in-memory reference to it (is // not an open file or current directory). static void itrunc(struct inode *ip) { int i, j; struct buf *bp; uint *a; uint* addr_ptr, *temp; for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } addr_ptr = &(ip->addrs[NDIRECT]); while(*addr_ptr) { bp = bread(ip->dev, *addr_ptr); a = (uint*)bp->data; for(j = 0; j < NINDIRECT - 1; j++){ if(a[j]) bfree(ip->dev, a[j]); } temp = &(a[NINDIRECT - 1]); brelse(bp); bfree(ip->dev, *addr_ptr); *addr_ptr = 0; addr_ptr = temp; } ip->size = 0; iupdate(ip); }
/* * write data to a regular file. * */ int writei(struct inode *ip, char *buf, uint off, uint cnt){ struct buf *bp; uint tot=0, m=0, bn=0; if (off+cnt < off){ return -1; } if (off+cnt > MAX_FILESIZ) { cnt = MAX_FILESIZ - off; } // do write. for(tot=0; tot<cnt; tot+=m, off+=m, buf+=m){ m = min(cnt - tot, BLK - off%BLK); bn = bmap(ip, off/BLK, 1); if (bn==0) { panic("bad block."); } else { bp = bread(ip->i_dev, bn); // note here! memcpy(bp->b_data + off%BLK, buf, m); bwrite(bp); brelse(bp); } } // adjust the inode's file size if (cnt > 0 && off > ip->i_size) { ip->i_size = off; iupdate(ip); } return cnt; }
// PAGEBREAK! // Write data to inode. int writei(struct inode *ip, char *src, uint off, uint n) { uint tot, m; struct buf *bp; //cprintf("inside writei: type=%x major=%x, func addr: %x\n", ip->type, ip->major, devsw[ip->major].write); if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; //cprintf("before calling consolewrite: major=%x, func addr: %x\n", ip->major, devsw[ip->major].write); return devsw[ip->major].write(ip, src, n); } if(off > ip->size || off + n < off) return -1; if(off + n > MAXFILE*BSIZE) return -1; for(tot=0; tot<n; tot+=m, off+=m, src+=m){ bp = bread(ip->dev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); log_write(bp); brelse(bp); } if(n > 0 && off > ip->size){ ip->size = off; iupdate(ip); } return n; }
/* * get an inode into the cache. if no inode exists for this qid, create one * from an unused qid/inode map. */ Ibuf * iget(Icache *ic, Qid qid) { Imap *m, *me; Ibuf *b; /* * find map entry with same qid.path */ for(m = ic->map, me = &ic->map[ic->nino]; m < me; m++) if(m->inuse && m->qid.path==qid.path){ if(m->qid.vers != qid.vers){ /* * our info is old, forget it */ DPRINT(2, "updating old file %llu.%lu\n", qid.path, qid.vers); m->qid = qid; iupdate(ic, m - ic->map, qid); } break; } /* * if an already existing inode, just get it */ if(m != me) return iread(ic, m - ic->map); /* * create a new inode, throw out the least recently used inode * if necessary */ m = (Imap*)ic->mlru.lnext; if(m->inuse){ DPRINT(2, "superceding file %llu.%ld by %llu.%ld\n", m->qid.path, m->qid.vers, qid.path, qid.vers); if(iremove(ic, m - ic->map) < 0) return 0; } if(statson) cfsstat.ninsert++; /* * init inode and write to disk */ DPRINT(2, "new file %llu.%ld ino %ld\n", qid.path, qid.vers, m - ic->map); b = ialloc(ic, m - ic->map); b->inode.inuse = m->inuse = 1; b->inode.qid = qid; b->inode.length = 0x7fffffffffffffffLL; m->qid = qid; b->inode.ptr.bno = Notabno; iwrite(ic, b); return b; }
/* * Discard inode's content. * Called from routines like open(), iput(). * */ int itrunc(struct inode *ip){ int i,j; ushort dev; struct buf *bp, *bp2; char *zmap, *zmap2; // only regular file but not directory can be truncated if (!(ip->i_mode & S_IFREG) || (ip->i_mode & S_IFDIR)) { return -1; } dev = ip->i_dev; for (i=0; i<7; i++){ if (ip->i_zone[i]!=0){ bfree(dev, ip->i_zone[i]); ip->i_flag |= I_DIRTY; ip->i_zone[i] = 0; } } /* -------------------------- */ if (ip->i_zone[7] != 0){ bp = bread(dev, ip->i_zone[7]); zmap = bp->b_data; for (i=0; i<NINDBLK; i++){ if(zmap[i] != 0){ bfree(dev, zmap[i]); } } bfree(dev, ip->i_zone[7]); ip->i_zone[7] = 0; brelse(bp); } /* -------------------------- */ if (ip->i_zone[8] != 0){ bp = bread(dev, ip->i_zone[8]); zmap = bp->b_data; for (i=0; i<NINDBLK; i++) { if (zmap[i] != 0){ bp2 = bread(dev, zmap[i]); zmap2 = bp2->b_data; for (j=0; j<NINDBLK; j++) { if (zmap2[j] != 0){ bfree(dev, zmap2[j]); } } brelse(bp2); bfree(dev, zmap[i]); } } brelse(bp); bfree(dev, ip->i_zone[8]); ip->i_zone[8] = 0; } ip->i_size = 0; iupdate(ip); return 0; }
struct inode* kernel_create(char *path, short type, short major, short minor) { uint off; struct inode *ip, *dp; char name[DIRSIZ]; //cprintf("nameiparent path: %s\n",path); if((dp = nameiparent(path, name)) == 0) return 0; ilock(dp); if((ip = dirlookup(dp, name, &off)) != 0){ iunlockput(dp); ilock(ip); if(type == T_FILE && ip->type == T_FILE) return ip; iunlockput(ip); return 0; } if((ip = ialloc(dp->dev, type)) == 0) panic("create: ialloc"); ilock(ip); ip->major = major; ip->minor = minor; ip->nlink = 1; iupdate(ip); if(type == T_DIR){ // Create . and .. entries. dp->nlink++; // for ".." iupdate(dp); // No ip->nlink++ for ".": avoid cyclic ref count. if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) panic("create dots"); } if(dirlink(dp, name, ip->inum) < 0) panic("create: dirlink"); iunlockput(dp); return ip; }
// Truncate inode (discard contents). // Only called when the inode has no links // to it (no directory entries referring to it) // and has no in-memory reference to it (is // not an open file or current directory). static void itrunc(struct inode *ip) { int i, j; struct buf *bp; struct buf *bp2; uint *a; uint *b; for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } if(ip->addrs[NDIRECT]){ bp = bread(ip->dev, ip->addrs[NDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]) bfree(ip->dev, a[j]); } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT]); ip->addrs[NDIRECT] = 0; } // part 1 delete files if(ip->addrs[NDIRECT+1]) { bp = bread(ip->dev, ip->addrs[NDIRECT+1]); a = (uint*)bp->data; for(i = 0; i < NINDIRECT; i++){ if(a[i]) { bp2 = bread(ip->dev, a[i]); b = (uint*)bp2->data; for(j = 0; j < NINDIRECT; j++) { if(b[j]) bfree(ip->dev, b[j]); } brelse(bp2); bfree(ip->dev, a[i]); a[i] = 0; } } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT+1]); ip->addrs[NDIRECT+1] = 0; } ip->size = 0; iupdate(ip); }
// Truncate inode (discard contents). // Only called when the inode has no links // to it (no directory entries referring to it) // and has no in-memory reference to it (is // not an open file or current directory). static void itrunc(struct inode *ip) { int i, j; struct buf *bp, *bp2; uint *a, *a2; for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } if(ip->addrs[NDIRECT]){ bp = bread(ip->dev, ip->addrs[NDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]) bfree(ip->dev, a[j]); } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT]); ip->addrs[NDIRECT] = 0; } /*vvv TASK 1.1 vvv*/ if(ip->indirect2){ bp = bread(ip->dev, ip->indirect2); a = (uint*)bp->data; for(i = 0; i < NINDIRECT; i++){ if(a[i]){ bp2 = bread(ip->dev, a[i]); a2 = (uint*)bp2->data; for(j = 0; j < NINDIRECT; j++){ if(a2[j]) bfree(ip->dev, a2[j]); } brelse(bp2); bfree(ip->dev, a[i]); } } brelse(bp); bfree(ip->dev, ip->indirect2); ip->indirect2 = 0; } /*^^^^^^^^^^^^^^^^^^*/ ip->size = 0; iupdate(ip); }
/* * open a file. flag indicated opened type like O_RDONLY, O_TRUNC, O_CREAT and blah. And * mode only used in the O_CREAT scenary, indicated the file (inode) type. * * each proc has got one user file table(p_ofile[NOFILE]), it's each entry is also a number, * indicated the number in the system file table(file[NFILE]). when user opened a file, it * first allocate a user file table entry(aka. file descriptor), then attach it with a system * file table entry. It's reference count is increased in fork() or dup(). * */ int do_open(char *path, uint flag, uint mode){ struct inode *ip; struct file *fp; ushort dev; int fd; // on create a new file. if (flag & O_CREAT){ ip = namei(path, 1); // if file is not existing yet. if (ip->i_nlink==0) { ip->i_mode = mode; ip->i_uid = cu->p_euid; ip->i_gid = cu->p_egid; ip->i_mtime = time(); ip->i_nlink = 1; iupdate(ip); } } // an existing file. else { ip = namei(path, 0); if (ip == NULL){ syserr(ENFILE); return -1; } // TODO: check access // if it's a device file, the dev number is stored in zone[0]. dev = ip->i_zone[0]; switch(ip->i_mode & S_IFMT) { case S_IFBLK: (*bdevsw[MAJOR(dev)].d_open)(dev); break; case S_IFCHR: (*cdevsw[MAJOR(dev)].d_open)(dev); break; } } if (((fd=ufalloc())<0) || (fp=falloc(fd))==NULL) { iput(ip); return -1; } if (flag & O_TRUNC){ itrunc(ip); } unlk_ino(ip); fp->f_oflag = flag; fp->f_ino = ip; cu->p_fdflag[fd] = FD_CLOEXEC; return fd; }
// Truncate inode (discard contents). static void itrunc(struct inode *ip) { int i, j, k; struct buf *bp, *bp2; uint *a; for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } if(ip->addrs[INDIRECT]){ bp = bread(ip->dev, ip->addrs[INDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]) bfree(ip->dev, a[j]); } brelse(bp); ip->addrs[INDIRECT] = 0; } //free double indirect blocks -- NEW CODE if(ip->addrs[DINDIRECT]){ bp = bread(ip->dev, ip->addrs[DINDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]){ bp2 = bread(ip->dev, a[j]); uint* b = (uint*)bp2->data; for(k = 0; k < NINDIRECT; k++){ if(b[k]){ bfree(ip->dev, b[k]); } } bfree(ip->dev, a[j]); } } brelse(bp); ip->addrs[DINDIRECT] = 0; } ip->size = 0; iupdate(ip); }
/* * Drop a reference to an in-memory inode. If that was the last reference, the * inode cache entry can be recycled. * * If that was the last reference and the inode has no links to it, free the * inode (and its content) on disk. */ void iput(struct inode *ip) { acquire(&icache.lock); if (ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0) { /* inode has no links: truncate and free inode. */ if (ip->flags & I_BUSY) panic("iput busy"); ip->flags |= I_BUSY; release(&icache.lock); itrunc(ip); ip->type = 0; iupdate(ip); acquire(&icache.lock); ip->flags = 0; wakeup(ip); } ip->ref--; release(&icache.lock); }
// Drop a reference to an in-memory inode. // If that was the last reference, the inode cache entry can // be recycled. // If that was the last reference and the inode has no links // to it, free the inode (and its content) on disk. // All calls to iput() must be inside a transaction in // case it has to free the inode. void iput(struct inode* ip) { // cprintf("iput %d \n",ip->inum); acquire(&icache.lock); if (ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0) { // inode has no links and no other references: truncate and free. if (ip->flags & I_BUSY) panic("iput busy"); ip->flags |= I_BUSY; release(&icache.lock); itrunc(ip); ip->type = 0; iupdate(ip); acquire(&icache.lock); ip->flags = 0; wakeup(ip); } ip->ref--; release(&icache.lock); }
// Truncate inode (discard contents). // Only called after the last dirent referring // to this inode has been erased on disk. static void itrunc(struct inode *ip) { int i, j; struct buf *bp; uint *a; uint new_addr; for(i = 0; i < NDIRECT; i++){ if(ip->addrs[i]){ new_addr=ip->addrs[i]; if(ip->type == T_CHECKED){ new_addr = ip->addrs[i] & 0x00ffffff; } bfree(ip->dev, new_addr); ip->addrs[i] = 0; } } if(ip->addrs[NDIRECT]){ bp = bread(ip->dev, ip->addrs[NDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]){ new_addr = a[j]; if(ip->type == T_CHECKED){ new_addr = a[j] & 0x00ffffff; } bfree(ip->dev, a[j]); } } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT]); ip->addrs[NDIRECT] = 0; } ip->size = 0; iupdate(ip); }
/* write data to inode */ int iwrite(struct inode *ip, char *src, uint32_t off, uint32_t n) { uint32_t tot, m; struct buf *bp; /* is a char device? */ if (S_ISCHR(ip->mode)) { return dtable[ip->zone[0]].write(ip, src, n); } if (off > ip->size || off + n < off ) { panic("iwrite: incorrect offset or read length\n"); return ERROR; } if (off + n > MAXFILE*BSIZE) { panic("iwrite: size out of range\n"); return ERROR; } for (tot = 0; tot < n; tot += m, src += m, off += m) { bp = bread(ip->dev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memcpy(bp->data + off%BSIZE, src, m); bwrite(bp); brelse(bp); } /* if alloc new block to ip, update it's size */ // n > 0 ? if (n > 0 && off > ip->size) { ip->size = off; iupdate(ip); } return n; }
// Write data to inode. //TODO int writei(struct inode *ip, char *src, uint off, uint n) { uint tot, m; struct buf *bp, *bp2, *bp3; uint offset; if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; return devsw[ip->major].write(ip, src, n); } if(off > ip->logical_size || off + n < off) return -1; if(off + n > MAXFILE*BSIZE) n = MAXFILE*BSIZE - off; if(ip->type == T_MIRRORED){ for(tot=0; tot<n; tot+=m, off+=m, src+=m){ offset = off/BSIZE*3; /* if((offset == 0)|| (offset%3 == 0)) offset */ cprintf("write off/BSIZE is %d\n", off/BSIZE); cprintf("write mirror0 is %d\n", mbmap(ip, offset, 0)); cprintf("write mirror1 is %d\n", mbmap(ip, offset, 1)); cprintf("write mirror2 is %d\n", mbmap(ip, offset, 2)); bp = bread(ip->dev, mbmap(ip, offset, 0)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); cprintf("bp is %s\n", &bp->data); bwrite(bp); brelse(bp); bp2 = bread(ip->dev, mbmap(ip, offset, 1)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp2->data + off%BSIZE, src, m); cprintf("bp2 is %s\n", &bp2->data); bwrite(bp2); brelse(bp2); bp3 = bread(ip->dev, mbmap(ip, offset, 2)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp3->data + off%BSIZE, src, m); cprintf("bp3 is %s\n", &bp->data); bwrite(bp3); brelse(bp3); //cprintf("i'm here to write\n"); } } else{ for(tot=0; tot<n; tot+=m, off+=m, src+=m){ bp = bread(ip->dev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); bwrite(bp); brelse(bp); } } iupdate(ip); if(n > 0 && off > ip->logical_size){ ip->logical_size = off; iupdate(ip); } return n; }
void bupdate(void) { static win_t *lwin = NULL; int waiting, widthx = secs_getvar_int("winlistchars"), M = widthx, #ifdef ENABLE_FORCEASCII fascii = secs_getvar_int("forceascii"), #endif bb, line = 0; conn_t *conn = curconn; wbuddy_widthy = secs_getvar_int("winlistheight")*faimconf.wstatus.widthy/100; if (wbuddy_widthy > faimconf.wstatus.widthy) wbuddy_widthy = faimconf.wstatus.widthy; #ifdef ENABLE_FORCEASCII # define LINEDRAW(ch,as) ((fascii == 1) ? as : ch) #else # define LINEDRAW(ch,as) ch #endif #define ACS_ULCORNER_C LINEDRAW(ACS_ULCORNER,',') #define ACS_LLCORNER_C LINEDRAW(ACS_LLCORNER,'`') #define ACS_URCORNER_C LINEDRAW(ACS_URCORNER,'.') #define ACS_LRCORNER_C LINEDRAW(ACS_LRCORNER,'\'') #define ACS_LTEE_C LINEDRAW(ACS_LTEE,'+') #define ACS_RTEE_C LINEDRAW(ACS_RTEE,'+') #define ACS_BTEE_C LINEDRAW(ACS_BTEE,'+') #define ACS_TTEE_C LINEDRAW(ACS_TTEE,'+') #define ACS_HLINE_C LINEDRAW(ACS_HLINE,'-') #define ACS_VLINE_C LINEDRAW(ACS_VLINE,'|') #define ACS_PLUS_C LINEDRAW(ACS_PLUS,'+') #define ACS_RARROW_C LINEDRAW(ACS_RARROW,'>') nw_erase(&win_buddy); nw_vline(&win_buddy, ACS_VLINE_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS), wbuddy_widthy); bb = buddyc; buddyc = 0; if (conn == NULL) return; waiting = 0; if (inconn) { int autoclose = getvar_int(curconn, "autoclose"); assert(curconn->curbwin != NULL); if ((autoclose > 0) && (curconn->curbwin->et == BUDDY) && !USER_PERMANENT(curconn->curbwin->e.buddy) && (curconn->curbwin->waiting != 0)) curconn->curbwin->closetime = now + 60*autoclose; curconn->curbwin->waiting = 0; if ((curconn->curbwin->et == CHAT) && curconn->curbwin->e.chat->isaddressed) curconn->curbwin->e.chat->isaddressed = 0; } do { buddywin_t *bwin = conn->curbwin; char *lastgroup = NULL; int hidegroup = 0, autosort = getvar_int(conn, "autosort"); assert(conn->winname != NULL); if (line < wbuddy_widthy) { nw_move(&win_buddy, line, 0); if (line == 0) nw_addch(&win_buddy, ACS_ULCORNER_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS)); else nw_addch(&win_buddy, ACS_LTEE_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS)); nw_hline(&win_buddy, ACS_HLINE_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS), widthx); nw_move(&win_buddy, line++, widthx-strlen(conn->winname)); if (conn->online <= 0) { nw_printf(&win_buddy, C(WINLIST,BUDDY_OFFLINE), 1, " %s", conn->winname); if (line < wbuddy_widthy) { nw_move(&win_buddy, line++, 1); nw_printf(&win_buddy, C(WINLIST,TEXT), 1, "%s", " You are offline"); buddyc++; } } else nw_printf(&win_buddy, C(WINLIST,TEXT), 1, " %s", conn->winname); } buddyc++; if (bwin == NULL) continue; if (autosort == 2) { if (bwin->et == BUDDY) STRREPLACE(lastgroup, USER_GROUP(bwin->e.buddy)); else STRREPLACE(lastgroup, CHAT_GROUP); } bsort(conn); do { if ((inconn && (conn == curconn)) || bwin->waiting) { char buf[256], *group; int col = -1; assert(bwin->winname != NULL); buddyc++; if (bwin->et == BUDDY) { user_name(buf, sizeof(buf), conn, bwin->e.buddy); group = USER_GROUP(bwin->e.buddy); } else { snprintf(buf, sizeof(buf), "%s", bwin->winname); group = CHAT_GROUP; } if (autosort == 2) { if (strcmp(lastgroup, group) != 0) { if (line < wbuddy_widthy) { nw_move(&win_buddy, line++, widthx-strlen(group)-1); nw_printf(&win_buddy, C(WINLIST,TEXT), hidegroup?0:1, "%c%s%c", hidegroup?'<':'[', group, hidegroup?'>':']'); buddyc++; } STRREPLACE(lastgroup, group); } } if (bwin->waiting && !waiting) { char tmp[64]; if (conn == curconn) snprintf(tmp, sizeof(tmp), " [Ctrl-N to %s]", buf); else snprintf(tmp, sizeof(tmp), " [Ctrl-N to %s:%s]", conn->winname, buf); secs_setvar("ifpending", tmp); waiting = 1; } if (printtitle && bwin->waiting && (waiting < 2) && ((bwin->et == BUDDY) || ((bwin->et == CHAT) && bwin->e.chat->isaddressed))) { nw_titlef("[%s:%s]", conn->winname, buf); waiting = 2; } if (line >= wbuddy_widthy) continue; if (strlen(buf) > M) { buf[M-1] = '>'; buf[M] = 0; } if ((bwin->et == CHAT) && bwin->e.chat->isaddressed) { assert(bwin->waiting); col = C(WINLIST,BUDDY_ADDRESSED); } else if (bwin->waiting) if (bwin->et == BUDDY) col = C(WINLIST,BUDDY_ADDRESSED); else col = C(WINLIST,BUDDY_WAITING); else if (bwin->pouncec > 0) col = C(WINLIST,BUDDY_QUEUED); else switch (bwin->et) { case BUDDY: if (bwin->e.buddy->tag != NULL) col = CI(WINLIST,BUDDY_TAGGED); else if (bwin->e.buddy->offline) col = C(WINLIST,BUDDY_OFFLINE); else if (bwin->e.buddy->ismobile) col = C(WINLIST,BUDDY_MOBILE); else if (bwin->e.buddy->isaway) col = C(WINLIST,BUDDY_AWAY); else if (bwin->e.buddy->isidle) col = C(WINLIST,BUDDY_IDLE); else col = C(WINLIST,BUDDY); break; case CHAT: assert(bwin->e.chat != NULL); if (bwin->e.chat->offline) col = C(WINLIST,BUDDY_OFFLINE); else col = C(WINLIST,BUDDY); break; case TRANSFER: col = C(WINLIST,BUDDY); break; } assert(col != -1); if (bwin == curconn->curbwin) { int affect = col/COLOR_PAIRS, back; #if 0 if (faimconf.b[cIMWIN] == faimconf.b[cWINLIST]) back = (faimconf.b[cIMWIN]+1)%nw_COLORS; else back = faimconf.b[cIMWIN]; #else back = faimconf.b[cWINLISTHIGHLIGHT]; #endif col %= nw_COLORS; col += nw_COLORS*back; col += affect*COLOR_PAIRS; } nw_move(&win_buddy, line, 1); if ((col >= 2*COLOR_PAIRS) || (col < COLOR_PAIRS)) nw_printf(&win_buddy, col%COLOR_PAIRS, 1, "%*s", M, buf); else nw_printf(&win_buddy, col%COLOR_PAIRS, 0, "%*s", M, buf); if (bwin->waiting) { nw_move(&win_buddy, line, 0); nw_addch(&win_buddy, ACS_LTEE_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS)); nw_addch(&win_buddy, ACS_RARROW_C | A_BOLD | COLOR_PAIR(col%COLOR_PAIRS)); } line++; } assert(buddyc < 1000); } while ((bwin = bwin->next) != conn->curbwin); if (autosort == 2) { free(lastgroup); lastgroup = NULL; } else assert(lastgroup == NULL); } while ((conn = conn->next) != curconn); nw_move(&win_buddy, line-1, 0); if (line != 1) nw_addch(&win_buddy, ACS_LLCORNER_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS)); else nw_addch(&win_buddy, ACS_HLINE_C | A_BOLD | COLOR_PAIR(C(WINLIST,TEXT)%COLOR_PAIRS)); if (printtitle && (waiting != 2)) nw_titlef(""); if (waiting) buddyc = -buddyc; else secs_setvar("ifpending", ""); if (inconn) assert(curconn->curbwin != NULL); if ((buddyc != bb) || (inconn && (&(curconn->curbwin->nwin) != lwin)) || (!inconn && (&(curconn->nwin) != lwin))) { if (inconn) lwin = &(curconn->curbwin->nwin); else lwin = &(curconn->nwin); bb = buddyc - bb; buddyc = buddyc - bb; bb = buddyc + bb; naim_changetime(); buddyc = bb; } iupdate(); }
/* * Given an inode and a position within the corresponding file, locate the * block (not zone) number in which that position is to be found and return it. * returns 0 on error. * note: * the first 7 entry of ip->zones[] are direct pointers, ip->zone[7] is an indirect * pointer to a zone map, while ip->zone[8] is an double indirect pointer to a zone map. * note2: file extends only here. * * ip->i_size is adjusted in writei(); * * TODO: maybe we can remove all the updatei and bwrite stuff, but sync() required first. */ int bmap(struct inode *ip, ushort nr, uchar creat) { struct buf *bp, *bp2; short *zmap, *zmap2; ushort dev; if ((nr > MAX_FILESIZ) || ((nr > (ip->i_size/BLK) && (creat==0)))) { panic("blk nr too big."); } dev = ip->i_dev; if (nr<7){ // if the create flag is set if (ip->i_zone[nr]==0 && creat){ ip->i_zone[nr] = balloc(dev); ip->i_flag |= I_DIRTY; iupdate(ip); } return ip->i_zone[nr]; } nr -= 7; /*----------------------------*/ // read the indirect zone map if (nr<NINDBLK){ if (ip->i_zone[7]==0) { if (creat==0) { return 0; } // if the indirect block is null and creat is set ip->i_zone[7] = balloc(dev); bzero(dev, ip->i_zone[7]); ip->i_flag |= I_DIRTY; iupdate(ip); } bp = bread(dev, ip->i_zone[7]); zmap = (short *)bp->b_data; if (zmap[nr]==0 && creat) { zmap[nr] = balloc(dev); bwrite(bp); } brelse(bp); return zmap[nr]; } /*----------------------------*/ nr -= NINDBLK; // the double indirect zone map. // read the middle indirect zone map. if (ip->i_zone[8]==0) { // if the first indirect block is null and creat is set if (creat == 0) { return 0; } ip->i_zone[8] = balloc(dev); bzero(dev, ip->i_zone[8]); ip->i_flag |= I_DIRTY; iupdate(ip); } bp = bread(dev, ip->i_zone[8]); zmap = (short *)bp->b_data; if (zmap[nr/NINDBLK]==0) { if (creat==0) { brelse(bp); return 0; } // if the second indirect block is null and creat is set zmap[nr/NINDBLK] = balloc(dev); bzero(dev, zmap[nr/NINDBLK]); bwrite(bp); } // read the secondary indirect zone map. bp2 = bread(dev, zmap[nr/NINDBLK]); zmap2 = (short*)bp2->b_data; if ((zmap2[nr%NINDBLK]==0) & creat) { zmap2[nr%NINDBLK] = balloc(dev); bwrite(bp2); } brelse(bp); brelse(bp2); return zmap2[nr%NINDBLK]; }