Large files
fs.h
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define NDOUBLEINDIRECT ((NINDIRECT) * (NINDIRECT))
#define MAXFILE ((NDIRECT) + (NINDIRECT) + (NDOUBLEINDIRECT))
// On-disk inode structure
struct dinode
{
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT + 2]; // Data block addresses
};
file.h
struct inode
{
uint dev; // Device number
uint inum; // Inode number
int ref; // Reference count
struct sleeplock lock; // protects everything below here
int valid; // inode has been read from disk?
short type; // copy of disk inode
short major;
short minor;
short nlink;
uint size;
uint addrs[NDIRECT + 2];
};
fs.c
static uint bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if (bn < NDIRECT)
{
if ((addr = ip->addrs[bn]) == 0)
{
addr = balloc(ip->dev);
if (addr == 0)
return 0;
ip->addrs[bn] = addr;
}
return addr;
}
bn -= NDIRECT;
if (bn < NINDIRECT)
{
// Load indirect block, allocating if necessary.
if ((addr = ip->addrs[NDIRECT]) == 0)
{
addr = balloc(ip->dev);
if (addr == 0)
return 0;
ip->addrs[NDIRECT] = addr;
}
bp = bread(ip->dev, addr);
a = (uint *)bp->data;
if ((addr = a[bn]) == 0)
{
addr = balloc(ip->dev);
if (addr)
{
a[bn] = addr;
log_write(bp);
}
}
brelse(bp);
return addr;
}
bn -= NINDIRECT;
if (bn < NDOUBLEINDIRECT)
{
if ((addr = ip->addrs[NDIRECT + 1]) == 0)
{
addr = balloc(ip->dev);
if (addr == 0)
{
return 0;
}
ip->addrs[NDIRECT + 1] = addr;
}
bp = bread(ip->dev, addr);
a = (uint *)bp->data;
if ((addr = a[bn / NINDIRECT]) == 0)
{
addr = balloc(ip->dev);
if (addr)
{
a[bn / NINDIRECT] = addr;
log_write(bp);
}
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint *)bp->data;
if ((addr = a[bn % NINDIRECT]) == 0)
{
addr = balloc(ip->dev);
if (addr)
{
a[bn % NINDIRECT] = addr;
log_write(bp);
}
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
// Truncate inode (discard contents).
// Caller must hold ip->lock.
void itrunc(struct inode *ip)
{
int i, j;
struct buf *bp, *second_bp;
uint *a, *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;
}
if (ip->addrs[NDIRECT + 1])
{
bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
a = (uint *)bp->data;
for (int i = 0; i < NINDIRECT; i++)
{
if (a[i])
{
second_bp = bread(ip->dev, a[i]);
b = (uint *)second_bp->data;
for (int j = 0; j < NINDIRECT; j++)
{
if (b[j])
{
bfree(ip->dev, b[j]);
}
}
brelse(second_bp);
bfree(ip->dev, a[i]);
}
}
brelse(bp);
bfree(ip->dev, ip->addrs[NDIRECT + 1]);
ip->addrs[NDIRECT + 1] = 0;
}
ip->size = 0;
iupdate(ip);
}
Symbolic links
uint64 sys_symlink(void)
{
char target[MAXPATH], path[MAXPATH];
struct inode *ip;
if (argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0)
{
return -1;
}
begin_op();
if ((ip = namei(path)) != 0)
{
end_op();
return -1;
}
if ((ip = create(path, T_SYMLINK, 0, 0)) == 0)
{
end_op();
return -1;
}
if (writei(ip, 0, (uint64)target, 0, MAXPATH) < 0)
{
iunlockput(ip);
end_op();
return -1;
}
iunlockput(ip);
end_op();
return 0;
}
uint64 sys_open(void)
{
char path[MAXPATH], target[MAXPATH];
int fd, omode;
struct file *f;
struct inode *ip;
int n;
argint(1, &omode);
if ((n = argstr(0, path, MAXPATH)) < 0)
return -1;
begin_op();
if (omode & O_CREATE)
{
ip = create(path, T_FILE, 0, 0);
if (ip == 0)
{
end_op();
return -1;
}
}
else
{
if ((ip = namei(path)) == 0)
{
end_op();
return -1;
}
ilock(ip);
if (ip->type == T_DIR && omode != O_RDONLY)
{
iunlockput(ip);
end_op();
return -1;
}
}
if (ip->type == T_SYMLINK && (omode & O_NOFOLLOW) == 0)
{
int i;
for (i = 0; i < NSYMLINKS; i++)
{
if ((readi(ip, 0, (uint64)target, 0, MAXPATH)) < 0)
{
iunlockput(ip);
end_op();
return -1;
}
iunlockput(ip);
if((ip = namei(target)) == 0)
{
end_op();
return -1;
}
ilock(ip);
if (ip->type != T_SYMLINK)
{
break;
}
}
if (i >= NSYMLINKS)
{
iunlock(ip);
end_op();
return -1;
}
}
if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV))
{
iunlockput(ip);
end_op();
return -1;
}
if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0)
{
if (f)
fileclose(f);
iunlockput(ip);
end_op();
return -1;
}
if (ip->type == T_DEVICE)
{
f->type = FD_DEVICE;
f->major = ip->major;
}
else
{
f->type = FD_INODE;
f->off = 0;
}
f->ip = ip;
f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
if ((omode & O_TRUNC) && ip->type == T_FILE)
{
itrunc(ip);
}
iunlock(ip);
end_op();
return fd;
}