add directory kernel

This commit is contained in:
gohigh
2024-02-19 00:24:53 -05:00
parent eec934fe6c
commit a4964ba92d
749 changed files with 100620 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
AR =ar
AS =as
CC =gcc
LD =ld
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
-fno-defer-pop -nostdinc -I../include
CPP =gcc -E -nostdinc -I../include
.c.s:
$(CC) $(CFLAGS) \
-S -o $*.s $<
.c.o:
$(CC) $(CFLAGS) \
-c -o $*.o $<
.s.o:
$(AS) -o $*.o $<
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
fcntl.o ioctl.o select.o
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
cd minix; make clean
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
cp tmp_make Makefile
cd minix; make dep
### Dependencies:
block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h
buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/system.h \
../include/asm/io.h
char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h ../include/asm/io.h
exec.o : exec.c ../include/signal.h ../include/sys/types.h \
../include/errno.h ../include/string.h ../include/sys/stat.h \
../include/a.out.h ../include/linux/fs.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h
fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
../include/fcntl.h ../include/sys/stat.h
file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
inode.o : inode.c ../include/string.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \
../include/asm/system.h
ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h
namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/linux/minix_fs.h ../include/asm/segment.h ../include/string.h \
../include/fcntl.h ../include/errno.h ../include/const.h \
../include/sys/stat.h
open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h
pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
../include/errno.h ../include/termios.h ../include/fcntl.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/asm/segment.h
read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \
../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h
select.o : select.c ../include/linux/fs.h ../include/sys/types.h \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
../include/asm/system.h ../include/sys/stat.h ../include/string.h \
../include/const.h ../include/errno.h
stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h
super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/linux/minix_fs.h \
../include/asm/system.h ../include/errno.h ../include/sys/stat.h

View File

@@ -0,0 +1,93 @@
/*
* linux/fs/block_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/system.h>
extern int *blk_size[];
int block_write(struct inode * inode, struct file * filp, char * buf, int count)
{
int block = filp->f_pos >> BLOCK_SIZE_BITS;
int offset = filp->f_pos & (BLOCK_SIZE-1);
int chars;
int written = 0;
int size;
unsigned int dev;
struct buffer_head * bh;
register char * p;
dev = inode->i_rdev;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)];
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
return written;
chars = BLOCK_SIZE - offset;
if (chars > count)
chars=count;
if (chars == BLOCK_SIZE)
bh = getblk(dev,block);
else
bh = breada(dev,block,block+1,block+2,-1);
block++;
if (!bh)
return written?written:-EIO;
p = offset + bh->b_data;
offset = 0;
filp->f_pos += chars;
written += chars;
count -= chars;
while (chars-->0)
*(p++) = get_fs_byte(buf++);
bh->b_dirt = 1;
brelse(bh);
}
return written;
}
int block_read(struct inode * inode, struct file * filp, char * buf, int count)
{
unsigned int block = filp->f_pos >> BLOCK_SIZE_BITS;
unsigned int offset = filp->f_pos & (BLOCK_SIZE-1);
unsigned int chars;
unsigned int size;
unsigned int dev;
int read = 0;
struct buffer_head * bh;
register char * p;
dev = inode->i_rdev;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)];
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
return read;
chars = BLOCK_SIZE-offset;
if (chars > count)
chars = count;
if (!(bh = breada(dev,block,block+1,block+2,-1)))
return read?read:-EIO;
block++;
p = offset + bh->b_data;
offset = 0;
filp->f_pos += chars;
read += chars;
count -= chars;
while (chars-->0)
put_fs_byte(*(p++),buf++);
brelse(bh);
}
return read;
}

View File

@@ -0,0 +1,426 @@
/*
* linux/fs/buffer.c
*
* (C) 1991 Linus Torvalds
*/
/*
* 'buffer.c' implements the buffer-cache functions. Race-conditions have
* been avoided by NEVER letting a interrupt change a buffer (except for the
* data, of course), but instead letting the caller do it. NOTE! As interrupts
* can wake up a caller, some cli-sti sequences are needed to check for
* sleep-on-calls. These should be extremely quick, though (I hope).
*/
/*
* NOTE! There is one discordant note here: checking floppies for
* disk change. This is where it fits best, I think, as it should
* invalidate changed floppy-disk-caches.
*/
#include <stdarg.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/io.h>
extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list;
static struct task_struct * buffer_wait = NULL;
int NR_BUFFERS = 0;
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
static void sync_buffers(int dev)
{
int i;
struct buffer_head * bh;
bh = free_list;
for (i=0 ; i<NR_BUFFERS ; i++,bh = bh->b_next_free) {
#if 0
if (dev && (bh->b_dev != dev))
continue;
#endif
wait_on_buffer(bh);
#if 0
if (dev && (bh->b_dev != dev))
continue;
#endif
if (bh->b_dirt)
ll_rw_block(WRITE,bh);
}
}
int sys_sync(void)
{
sync_inodes(); /* write out inodes into buffers */
sync_buffers(0);
return 0;
}
int sync_dev(int dev)
{
sync_buffers(dev);
sync_inodes();
sync_buffers(dev);
return 0;
}
void inline invalidate_buffers(int dev)
{
int i;
struct buffer_head * bh;
bh = start_buffer;
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
if (bh->b_dev != dev)
continue;
wait_on_buffer(bh);
if (bh->b_dev == dev)
bh->b_uptodate = bh->b_dirt = 0;
}
}
/*
* This routine checks whether a floppy has been changed, and
* invalidates all buffer-cache-entries in that case. This
* is a relatively slow routine, so we have to try to minimize using
* it. Thus it is called only upon a 'mount' or 'open'. This
* is the best way of combining speed and utility, I think.
* People changing diskettes in the middle of an operation deserve
* to loose :-)
*
* NOTE! Although currently this is only for floppies, the idea is
* that any additional removable block-device will use this routine,
* and that mount/open needn't know that floppies/whatever are
* special.
*/
void check_disk_change(int dev)
{
int i;
if (MAJOR(dev) != 2)
return;
if (!floppy_change(dev & 0x03))
return;
for (i=0 ; i<NR_SUPER ; i++)
if (super_block[i].s_dev == dev)
put_super(super_block[i].s_dev);
invalidate_inodes(dev);
invalidate_buffers(dev);
}
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
static inline void remove_from_hash_queue(struct buffer_head * bh)
{
if (bh->b_next)
bh->b_next->b_prev = bh->b_prev;
if (bh->b_prev)
bh->b_prev->b_next = bh->b_next;
if (hash(bh->b_dev,bh->b_blocknr) == bh)
hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
bh->b_next = bh->b_prev = NULL;
}
static inline void remove_from_free_list(struct buffer_head * bh)
{
if (!(bh->b_prev_free) || !(bh->b_next_free))
panic("Free block list corrupted");
bh->b_prev_free->b_next_free = bh->b_next_free;
bh->b_next_free->b_prev_free = bh->b_prev_free;
if (free_list == bh)
free_list = bh->b_next_free;
bh->b_next_free = bh->b_prev_free = NULL;
}
static inline void remove_from_queues(struct buffer_head * bh)
{
remove_from_hash_queue(bh);
remove_from_free_list(bh);
}
static inline void put_first_free(struct buffer_head * bh)
{
if (!bh || (bh == free_list))
return;
remove_from_free_list(bh);
/* add to front of free list */
bh->b_next_free = free_list;
bh->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = bh;
free_list->b_prev_free = bh;
free_list = bh;
}
static inline void put_last_free(struct buffer_head * bh)
{
if (!bh)
return;
if (bh == free_list) {
free_list = bh->b_next_free;
return;
}
remove_from_free_list(bh);
/* add to back of free list */
bh->b_next_free = free_list;
bh->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = bh;
free_list->b_prev_free = bh;
}
static inline void insert_into_queues(struct buffer_head * bh)
{
/* put at end of free list */
bh->b_next_free = free_list;
bh->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = bh;
free_list->b_prev_free = bh;
/* put the buffer in new hash-queue if it has a device */
bh->b_prev = NULL;
bh->b_next = NULL;
if (!bh->b_dev)
return;
bh->b_next = hash(bh->b_dev,bh->b_blocknr);
hash(bh->b_dev,bh->b_blocknr) = bh;
bh->b_next->b_prev = bh;
}
static struct buffer_head * find_buffer(int dev, int block)
{
struct buffer_head * tmp;
for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
if (tmp->b_dev==dev && tmp->b_blocknr==block)
return tmp;
return NULL;
}
/*
* Why like this, I hear you say... The reason is race-conditions.
* As we don't lock buffers (unless we are readint them, that is),
* something might happen to it while we sleep (ie a read-error
* will force it bad). This shouldn't really happen currently, but
* the code is ready.
*/
struct buffer_head * get_hash_table(int dev, int block)
{
struct buffer_head * bh;
for (;;) {
if (!(bh=find_buffer(dev,block)))
return NULL;
bh->b_count++;
wait_on_buffer(bh);
if (bh->b_dev == dev && bh->b_blocknr == block) {
put_last_free(bh);
return bh;
}
bh->b_count--;
}
}
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
* so it should be much more efficient than it looks.
*
* The algoritm is changed: hopefully better, and an elusive bug removed.
*
* 14.02.92: changed it to sync dirty buffers a bit: better performance
* when the filesystem starts to get full of dirty blocks (I hope).
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
struct buffer_head * getblk(int dev,int block)
{
struct buffer_head * bh, * tmp;
int buffers;
repeat:
if (bh = get_hash_table(dev,block))
return bh;
buffers = NR_BUFFERS;
tmp = free_list;
do {
tmp = tmp->b_next_free;
if (tmp->b_count)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) {
bh = tmp;
if (!BADNESS(tmp))
break;
}
if (tmp->b_dirt)
ll_rw_block(WRITEA,tmp);
/* and repeat until we find something good */
} while (buffers--);
if (!bh) {
sleep_on(&buffer_wait);
goto repeat;
}
wait_on_buffer(bh);
if (bh->b_count)
goto repeat;
while (bh->b_dirt) {
sync_dev(bh->b_dev);
wait_on_buffer(bh);
if (bh->b_count)
goto repeat;
}
/* NOTE!! While we slept waiting for this block, somebody else might */
/* already have added "this" block to the cache. check it */
if (find_buffer(dev,block))
goto repeat;
/* OK, FINALLY we know that this buffer is the only one of it's kind, */
/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
bh->b_count=1;
bh->b_dirt=0;
bh->b_uptodate=0;
remove_from_queues(bh);
bh->b_dev=dev;
bh->b_blocknr=block;
insert_into_queues(bh);
return bh;
}
void brelse(struct buffer_head * buf)
{
if (!buf)
return;
wait_on_buffer(buf);
if (!(buf->b_count--))
panic("Trying to free free buffer");
wake_up(&buffer_wait);
}
/*
* bread() reads a specified block and returns the buffer that contains
* it. It returns NULL if the block was unreadable.
*/
struct buffer_head * bread(int dev,int block)
{
struct buffer_head * bh;
if (!(bh=getblk(dev,block)))
panic("bread: getblk returned NULL\n");
if (bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return NULL;
}
#define COPYBLK(from,to) \
__asm__("cld\n\t" \
"rep\n\t" \
"movsl\n\t" \
::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
:"cx","di","si")
/*
* bread_page reads four buffers into memory at the desired address. It's
* a function of its own, as there is some speed to be got by reading them
* all at the same time, not waiting for one to be read, and then another
* etc.
*/
void bread_page(unsigned long address,int dev,int b[4])
{
struct buffer_head * bh[4];
int i;
for (i=0 ; i<4 ; i++)
if (b[i]) {
if (bh[i] = getblk(dev,b[i]))
if (!bh[i]->b_uptodate)
ll_rw_block(READ,bh[i]);
} else
bh[i] = NULL;
for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
if (bh[i]) {
wait_on_buffer(bh[i]);
if (bh[i]->b_uptodate)
COPYBLK((unsigned long) bh[i]->b_data,address);
brelse(bh[i]);
}
}
/*
* Ok, breada can be used as bread, but additionally to mark other
* blocks for reading as well. End the argument list with a negative
* number.
*/
struct buffer_head * breada(int dev,int first, ...)
{
va_list args;
struct buffer_head * bh, *tmp;
va_start(args,first);
if (!(bh=getblk(dev,first)))
panic("bread: getblk returned NULL\n");
if (!bh->b_uptodate)
ll_rw_block(READ,bh);
while ((first=va_arg(args,int))>=0) {
tmp=getblk(dev,first);
if (tmp) {
if (!tmp->b_uptodate)
ll_rw_block(READA,bh);
tmp->b_count--;
}
}
va_end(args);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return (NULL);
}
void buffer_init(long buffer_end)
{
struct buffer_head * h = start_buffer;
void * b;
int i;
if (buffer_end == 1<<20)
b = (void *) (640*1024);
else
b = (void *) buffer_end;
while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
h->b_dev = 0;
h->b_dirt = 0;
h->b_count = 0;
h->b_lock = 0;
h->b_uptodate = 0;
h->b_wait = NULL;
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = (char *) b;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
NR_BUFFERS++;
if (b == (void *) 0x100000)
b = (void *) 0xA0000;
}
h--;
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
for (i=0;i<NR_HASH;i++)
hash_table[i] = NULL;
}

View File

@@ -0,0 +1,136 @@
/*
* linux/fs/char_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <sys/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/io.h>
extern int tty_read(unsigned minor,char * buf,int count,unsigned short flags);
extern int tty_write(unsigned minor,char * buf,int count);
typedef (*crw_ptr)(int,unsigned,char *,int,off_t *,unsigned short);
static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags)
{
return ((rw==READ)?tty_read(minor,buf,count,flags):
tty_write(minor,buf,count));
}
static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos, unsigned short flags)
{
if (current->tty<0)
return -EPERM;
return rw_ttyx(rw,current->tty,buf,count,pos,flags);
}
static int rw_ram(int rw,char * buf, int count, off_t *pos)
{
return -EIO;
}
static int rw_mem(int rw,char * buf, int count, off_t * pos)
{
return -EIO;
}
static int rw_kmem(int rw,char * buf, int count, off_t * pos)
{
/* kmem by Damiano */
int i = *pos; /* Current position where to read */
/* i can go from 0 to LOW_MEM (See include/linux/mm.h */
/* I am not shure about it but it doesn't mem fault :-) */
while ( (count-- > 0) && (i <LOW_MEM) ) {
if (rw==READ)
put_fs_byte( *(char *)i ,buf++);
else
return (-EIO);
i++;
}
i -= *pos; /* Count how many read or write */
*pos += i; /* Update position */
return (i); /* Return number read */
}
static int rw_port(int rw,char * buf, int count, off_t * pos)
{
int i=*pos;
while (count-->0 && i<65536) {
if (rw==READ)
put_fs_byte(inb(i),buf++);
else
outb(get_fs_byte(buf++),i);
i++;
}
i -= *pos;
*pos += i;
return i;
}
static int rw_memory(int rw, unsigned minor, char * buf, int count,
off_t * pos, unsigned short flags)
{
switch(minor) {
case 0:
return rw_ram(rw,buf,count,pos);
case 1:
return rw_mem(rw,buf,count,pos);
case 2:
return rw_kmem(rw,buf,count,pos);
case 3:
return (rw==READ)?0:count; /* rw_null */
case 4:
return rw_port(rw,buf,count,pos);
default:
return -EIO;
}
}
#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
static crw_ptr crw_table[]={
NULL, /* nodev */
rw_memory, /* /dev/mem etc */
NULL, /* /dev/fd */
NULL, /* /dev/hd */
rw_ttyx, /* /dev/ttyx */
rw_tty, /* /dev/tty */
NULL, /* /dev/lp */
NULL}; /* unnamed pipes */
int char_read(struct inode * inode, struct file * filp, char * buf, int count)
{
unsigned int major,minor;
crw_ptr call_addr;
major = MAJOR(inode->i_rdev);
minor = MINOR(inode->i_rdev);
if (major >= NRDEVS)
return -ENODEV;
if (!(call_addr = crw_table[major]))
return -ENODEV;
return call_addr(READ,minor,buf,count,&filp->f_pos,filp->f_flags);
}
int char_write(struct inode * inode, struct file * filp, char * buf, int count)
{
unsigned int major,minor;
crw_ptr call_addr;
major = MAJOR(inode->i_rdev);
minor = MINOR(inode->i_rdev);
if (major >= NRDEVS)
return -ENODEV;
if (!(call_addr=crw_table[major]))
return -ENODEV;
return call_addr(WRITE,minor,buf,count,&filp->f_pos,filp->f_flags);
}

View File

@@ -0,0 +1,390 @@
/*
* linux/fs/exec.c
*
* (C) 1991 Linus Torvalds
*/
/*
* #!-checking implemented by tytso.
*/
/*
* Demand-loading implemented 01.12.91 - no need to read anything but
* the header into memory. The inode of the executable is put into
* "current->executable", and page faults do the actual loading. Clean.
*
* Once more I can proudly say that linux stood up to being changed: it
* was less than 2 hours work to get demand-loading completely implemented.
*/
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <a.out.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/segment.h>
extern int sys_exit(int exit_code);
extern int sys_close(int fd);
/*
* MAX_ARG_PAGES defines the number of pages allocated for arguments
* and envelope for the new program. 32 should suffice, this gives
* a maximum env+arg of 128kB !
*/
#define MAX_ARG_PAGES 32
int sys_uselib(const char * library)
{
struct inode * inode;
unsigned long base;
if (get_limit(0x17) != TASK_SIZE)
return -EINVAL;
if (library) {
if (!(inode=namei(library))) /* get library inode */
return -ENOENT;
} else
inode = NULL;
/* we should check filetypes (headers etc), but we don't */
iput(current->library);
current->library = NULL;
base = get_base(current->ldt[2]);
base += LIBRARY_OFFSET;
free_page_tables(base,LIBRARY_SIZE);
current->library = inode;
return 0;
}
/*
* create_tables() parses the env- and arg-strings in new user
* memory and creates the pointer tables from them, and puts their
* addresses on the "stack", returning the new stack pointer value.
*/
static unsigned long * create_tables(char * p,int argc,int envc)
{
unsigned long *argv,*envp;
unsigned long * sp;
sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
sp -= envc+1;
envp = sp;
sp -= argc+1;
argv = sp;
put_fs_long((unsigned long)envp,--sp);
put_fs_long((unsigned long)argv,--sp);
put_fs_long((unsigned long)argc,--sp);
while (argc-->0) {
put_fs_long((unsigned long) p,argv++);
while (get_fs_byte(p++)) /* nothing */ ;
}
put_fs_long(0,argv);
while (envc-->0) {
put_fs_long((unsigned long) p,envp++);
while (get_fs_byte(p++)) /* nothing */ ;
}
put_fs_long(0,envp);
return sp;
}
/*
* count() counts the number of arguments/envelopes
*/
static int count(char ** argv)
{
int i=0;
char ** tmp;
if (tmp = argv)
while (get_fs_long((unsigned long *) (tmp++)))
i++;
return i;
}
/*
* 'copy_string()' copies argument/envelope strings from user
* memory to free pages in kernel mem. These are in a format ready
* to be put directly into the top of new user memory.
*
* Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
* whether the string and the string array are from user or kernel segments:
*
* from_kmem argv * argv **
* 0 user space user space
* 1 kernel space user space
* 2 kernel space kernel space
*
* We do this by playing games with the fs segment register. Since it
* it is expensive to load a segment register, we try to avoid calling
* set_fs() unless we absolutely have to.
*/
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
unsigned long p, int from_kmem)
{
char *tmp, *pag;
int len, offset = 0;
unsigned long old_fs, new_fs;
if (!p)
return 0; /* bullet-proofing */
new_fs = get_ds();
old_fs = get_fs();
if (from_kmem==2)
set_fs(new_fs);
while (argc-- > 0) {
if (from_kmem == 1)
set_fs(new_fs);
if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
panic("argc is wrong");
if (from_kmem == 1)
set_fs(old_fs);
len=0; /* remember zero-padding */
do {
len++;
} while (get_fs_byte(tmp++));
if (p < len) { /* this shouldn't happen - 128kB */
set_fs(old_fs);
return 0;
}
while (len) {
--p; --tmp; --len;
if (--offset < 0) {
offset = p % PAGE_SIZE;
if (from_kmem==2)
set_fs(old_fs);
if (!(pag = (char *) page[p/PAGE_SIZE]) &&
!(pag = (char *) page[p/PAGE_SIZE] =
(unsigned long *) get_free_page()))
return 0;
if (from_kmem==2)
set_fs(new_fs);
}
*(pag + offset) = get_fs_byte(tmp);
}
}
if (from_kmem==2)
set_fs(old_fs);
return p;
}
static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
{
unsigned long code_limit,data_limit,code_base,data_base;
int i;
code_limit = TASK_SIZE;
data_limit = TASK_SIZE;
code_base = get_base(current->ldt[1]);
data_base = code_base;
set_base(current->ldt[1],code_base);
set_limit(current->ldt[1],code_limit);
set_base(current->ldt[2],data_base);
set_limit(current->ldt[2],data_limit);
/* make sure fs points to the NEW data segment */
__asm__("pushl $0x17\n\tpop %%fs"::);
data_base += data_limit - LIBRARY_SIZE;
for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
data_base -= PAGE_SIZE;
if (page[i])
put_dirty_page(page[i],data_base);
}
return data_limit;
}
/*
* 'do_execve()' executes a new program.
*
* NOTE! We leave 4MB free at the top of the data-area for a loadable
* library.
*/
int do_execve(unsigned long * eip,long tmp,char * filename,
char ** argv, char ** envp)
{
struct inode * inode;
struct buffer_head * bh;
struct exec ex;
unsigned long page[MAX_ARG_PAGES];
int i,argc,envc;
int e_uid, e_gid;
int retval;
int sh_bang = 0;
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
if ((0xffff & eip[1]) != 0x000f)
panic("execve called from supervisor mode");
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
page[i]=0;
if (!(inode=namei(filename))) /* get executables inode */
return -ENOENT;
argc = count(argv);
envc = count(envp);
restart_interp:
if (!S_ISREG(inode->i_mode)) { /* must be regular file */
retval = -EACCES;
goto exec_error2;
}
i = inode->i_mode;
/* make sure we don't let suid, sgid files be ptraced. */
if (current->flags & PF_PTRACED) {
e_uid = current->euid;
e_gid = current->egid;
} else {
e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
}
if (current->euid == inode->i_uid)
i >>= 6;
else if (in_group_p(inode->i_gid))
i >>= 3;
if (!(i & 1) &&
!((inode->i_mode & 0111) && suser())) {
retval = -EACCES;
goto exec_error2;
}
if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
retval = -EACCES;
goto exec_error2;
}
ex = *((struct exec *) bh->b_data); /* read exec-header */
if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
/*
* This section does the #! interpretation.
* Sorta complicated, but hopefully it will work. -TYT
*/
char buf[128], *cp, *interp, *i_name, *i_arg;
unsigned long old_fs;
strncpy(buf, bh->b_data+2, 127);
brelse(bh);
iput(inode);
buf[127] = '\0';
if (cp = strchr(buf, '\n')) {
*cp = '\0';
for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
}
if (!cp || *cp == '\0') {
retval = -ENOEXEC; /* No interpreter name found */
goto exec_error1;
}
interp = i_name = cp;
i_arg = 0;
for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
if (*cp == '/')
i_name = cp+1;
}
if (*cp) {
*cp++ = '\0';
i_arg = cp;
}
/*
* OK, we've parsed out the interpreter name and
* (optional) argument.
*/
if (sh_bang++ == 0) {
p = copy_strings(envc, envp, page, p, 0);
p = copy_strings(--argc, argv+1, page, p, 0);
}
/*
* Splice in (1) the interpreter's name for argv[0]
* (2) (optional) argument to interpreter
* (3) filename of shell script
*
* This is done in reverse order, because of how the
* user environment and arguments are stored.
*/
p = copy_strings(1, &filename, page, p, 1);
argc++;
if (i_arg) {
p = copy_strings(1, &i_arg, page, p, 2);
argc++;
}
p = copy_strings(1, &i_name, page, p, 2);
argc++;
if (!p) {
retval = -ENOMEM;
goto exec_error1;
}
/*
* OK, now restart the process with the interpreter's inode.
*/
old_fs = get_fs();
set_fs(get_ds());
if (!(inode=namei(interp))) { /* get executables inode */
set_fs(old_fs);
retval = -ENOENT;
goto exec_error1;
}
set_fs(old_fs);
goto restart_interp;
}
brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
retval = -ENOEXEC;
goto exec_error2;
}
if (N_TXTOFF(ex) != BLOCK_SIZE) {
printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
retval = -ENOEXEC;
goto exec_error2;
}
if (!sh_bang) {
p = copy_strings(envc,envp,page,p,0);
p = copy_strings(argc,argv,page,p,0);
if (!p) {
retval = -ENOMEM;
goto exec_error2;
}
}
/* OK, This is the point of no return */
/* note that current->library stays unchanged by an exec */
if (current->executable)
iput(current->executable);
current->executable = inode;
current->signal = 0;
for (i=0 ; i<32 ; i++) {
current->sigaction[i].sa_mask = 0;
current->sigaction[i].sa_flags = 0;
if (current->sigaction[i].sa_handler != SIG_IGN)
current->sigaction[i].sa_handler = NULL;
}
for (i=0 ; i<NR_OPEN ; i++)
if ((current->close_on_exec>>i)&1)
sys_close(i);
current->close_on_exec = 0;
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
if (last_task_used_math == current)
last_task_used_math = NULL;
current->used_math = 0;
p += change_ldt(ex.a_text,page);
p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
p = (unsigned long) create_tables((char *)p,argc,envc);
current->brk = ex.a_bss +
(current->end_data = ex.a_data +
(current->end_code = ex.a_text));
current->start_stack = p;
current->suid = current->euid = e_uid;
current->sgid = current->egid = e_gid;
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
return 0;
exec_error2:
iput(inode);
exec_error1:
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(page[i]);
return(retval);
}

View File

@@ -0,0 +1,77 @@
/*
* linux/fs/fcntl.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <fcntl.h>
#include <sys/stat.h>
extern int sys_close(int fd);
static int dupfd(unsigned int fd, unsigned int arg)
{
if (fd >= NR_OPEN || !current->filp[fd])
return -EBADF;
if (arg >= NR_OPEN)
return -EINVAL;
while (arg < NR_OPEN)
if (current->filp[arg])
arg++;
else
break;
if (arg >= NR_OPEN)
return -EMFILE;
current->close_on_exec &= ~(1<<arg);
(current->filp[arg] = current->filp[fd])->f_count++;
return arg;
}
int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
if (newfd == oldfd)
return newfd;
sys_close(newfd);
return dupfd(oldfd,newfd);
}
int sys_dup(unsigned int fildes)
{
return dupfd(fildes,0);
}
int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
switch (cmd) {
case F_DUPFD:
return dupfd(fd,arg);
case F_GETFD:
return (current->close_on_exec>>fd)&1;
case F_SETFD:
if (arg&1)
current->close_on_exec |= (1<<fd);
else
current->close_on_exec &= ~(1<<fd);
return 0;
case F_GETFL:
return filp->f_flags;
case F_SETFL:
filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
return 0;
case F_GETLK: case F_SETLK: case F_SETLKW:
return -ENOSYS;
default:
return -EINVAL;
}
}

View File

@@ -0,0 +1,9 @@
/*
* linux/fs/file_table.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/fs.h>
struct file file_table[NR_FILE];

View File

@@ -0,0 +1,246 @@
/*
* linux/fs/inode.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
struct inode inode_table[NR_INODE]={{0,},};
extern void minix_read_inode(struct inode * inode);
extern void minix_write_inode(struct inode * inode);
static inline void wait_on_inode(struct inode * inode)
{
cli();
while (inode->i_lock)
sleep_on(&inode->i_wait);
sti();
}
static inline void lock_inode(struct inode * inode)
{
cli();
while (inode->i_lock)
sleep_on(&inode->i_wait);
inode->i_lock=1;
sti();
}
static inline void unlock_inode(struct inode * inode)
{
inode->i_lock=0;
wake_up(&inode->i_wait);
}
static void write_inode(struct inode * inode)
{
lock_inode(inode);
if (!inode->i_dirt || !inode->i_dev) {
unlock_inode(inode);
return;
}
minix_write_inode(inode);
unlock_inode(inode);
}
static void read_inode(struct inode * inode)
{
lock_inode(inode);
minix_read_inode(inode);
unlock_inode(inode);
}
int bmap(struct inode * inode, int block)
{
return minix_bmap(inode,block);
}
void invalidate_inodes(int dev)
{
int i;
struct inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
wait_on_inode(inode);
if (inode->i_dev == dev) {
if (inode->i_count)
printk("inode in use on removed disk\n\r");
inode->i_dev = inode->i_dirt = 0;
}
}
}
void sync_inodes(void)
{
int i;
struct inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
wait_on_inode(inode);
if (inode->i_dirt && !inode->i_pipe)
write_inode(inode);
}
}
void iput(struct inode * inode)
{
if (!inode)
return;
wait_on_inode(inode);
if (!inode->i_count)
panic("iput: trying to free free inode");
if (inode->i_pipe) {
wake_up(&inode->i_wait);
wake_up(&inode->i_wait2);
if (--inode->i_count)
return;
free_page(inode->i_size);
inode->i_count=0;
inode->i_dirt=0;
inode->i_pipe=0;
return;
}
if (!inode->i_dev) {
inode->i_count--;
return;
}
if (S_ISBLK(inode->i_mode)) {
sync_dev(inode->i_rdev);
wait_on_inode(inode);
}
repeat:
if (inode->i_count>1) {
inode->i_count--;
return;
}
if (!inode->i_nlink) {
minix_truncate(inode);
minix_free_inode(inode);
return;
}
if (inode->i_dirt) {
write_inode(inode); /* we can sleep - so do again */
wait_on_inode(inode);
goto repeat;
}
inode->i_count--;
return;
}
struct inode * get_empty_inode(void)
{
struct inode * inode;
static struct inode * last_inode = inode_table;
int i;
do {
inode = NULL;
for (i = NR_INODE; i ; i--) {
if (++last_inode >= inode_table + NR_INODE)
last_inode = inode_table;
if (!last_inode->i_count) {
inode = last_inode;
if (!inode->i_dirt && !inode->i_lock)
break;
}
}
if (!inode) {
for (i=0 ; i<NR_INODE ; i++)
printk("(%04x: %d (%o)) ",inode_table[i].i_dev,
inode_table[i].i_ino,inode_table[i].i_mode);
panic("No free inodes in mem");
}
wait_on_inode(inode);
while (inode->i_dirt) {
write_inode(inode);
wait_on_inode(inode);
}
} while (inode->i_count);
memset(inode,0,sizeof(*inode));
inode->i_count = 1;
return inode;
}
struct inode * get_pipe_inode(void)
{
struct inode * inode;
if (!(inode = get_empty_inode()))
return NULL;
if (!(inode->i_size=get_free_page())) {
inode->i_count = 0;
return NULL;
}
inode->i_count = 2; /* sum of readers/writers */
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
inode->i_pipe = 1;
return inode;
}
struct inode * iget(int dev,int nr)
{
struct inode * inode, * empty;
if (!dev)
panic("iget with dev==0");
empty = get_empty_inode();
inode = inode_table;
while (inode < NR_INODE+inode_table) {
if (inode->i_dev != dev || inode->i_ino != nr) {
inode++;
continue;
}
wait_on_inode(inode);
if (inode->i_dev != dev || inode->i_ino != nr) {
inode = inode_table;
continue;
}
inode->i_count++;
if (inode->i_mount) {
int i;
for (i = 0 ; i<NR_SUPER ; i++)
if (super_block[i].s_covered==inode)
break;
if (i >= NR_SUPER) {
printk("Mounted inode hasn't got sb\n");
if (empty)
iput(empty);
return inode;
}
iput(inode);
if (!(inode = super_block[i].s_mounted))
printk("iget: mounted dev has no rootinode\n");
else {
inode->i_count++;
wait_on_inode(inode);
}
}
if (empty)
iput(empty);
return inode;
}
if (!empty)
return (NULL);
inode = empty;
if (!(inode->i_sb = get_super(dev))) {
printk("iget: gouldn't get super-block\n\t");
iput(inode);
return NULL;
}
inode->i_dev = dev;
inode->i_ino = nr;
read_inode(inode);
return inode;
}

View File

@@ -0,0 +1,49 @@
/*
* linux/fs/ioctl.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <linux/sched.h>
extern int tty_ioctl(int dev, int cmd, int arg);
extern int pipe_ioctl(struct inode *pino, int cmd, int arg);
typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
static ioctl_ptr ioctl_table[]={
NULL, /* nodev */
NULL, /* /dev/mem */
NULL, /* /dev/fd */
NULL, /* /dev/hd */
tty_ioctl, /* /dev/ttyx */
tty_ioctl, /* /dev/tty */
NULL, /* /dev/lp */
NULL}; /* named pipes */
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
int dev,mode;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
if (filp->f_inode->i_pipe)
return (filp->f_mode&1)?pipe_ioctl(filp->f_inode,cmd,arg):-EBADF;
mode=filp->f_inode->i_mode;
if (!S_ISCHR(mode) && !S_ISBLK(mode))
return -EINVAL;
dev = filp->f_inode->i_rdev;
if (MAJOR(dev) >= NRDEVS)
return -ENODEV;
if (!ioctl_table[MAJOR(dev)])
return -ENOTTY;
return ioctl_table[MAJOR(dev)](dev,cmd,arg);
}

View File

@@ -0,0 +1,69 @@
AR =ar
AS =as
CC =gcc
LD =ld
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
-nostdinc -I../../include
CPP =gcc -E -nostdinc -I../../include
.c.s:
$(CC) $(CFLAGS) \
-S -o $*.s $<
.c.o:
$(CC) $(CFLAGS) \
-c -o $*.o $<
.s.o:
$(AS) -o $*.o $<
OBJS= minix_op.o bitmap.o truncate.o namei.o inode.o file_dev.o
minix.o: $(OBJS)
$(LD) -r -o minix.o $(OBJS)
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
cp tmp_make Makefile
### Dependencies:
bitmap.o : bitmap.c ../../include/string.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/linux/minix_fs.h
file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.h \
../../include/sys/types.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
../../include/time.h ../../include/sys/resource.h \
../../include/linux/minix_fs.h ../../include/asm/segment.h
inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \
../../include/sys/types.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
../../include/time.h ../../include/sys/resource.h \
../../include/linux/minix_fs.h ../../include/asm/system.h
minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \
../../include/linux/minix_fs.h
namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/linux/minix_fs.h \
../../include/asm/segment.h ../../include/string.h ../../include/fcntl.h \
../../include/errno.h ../../include/const.h ../../include/sys/stat.h
truncate.o : truncate.c ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/linux/minix_fs.h \
../../include/linux/tty.h ../../include/termios.h ../../include/errno.h \
../../include/fcntl.h ../../include/sys/stat.h

View File

@@ -0,0 +1,184 @@
/*
* linux/fs/bitmap.c
*
* (C) 1991 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <string.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
#define set_bit(nr,addr) ({\
char res; \
__asm__ __volatile__("btsl %1,%2\n\tsetb %0": \
"=q" (res):"r" (nr),"m" (*(addr))); \
res;})
#define clear_bit(nr,addr) ({\
char res; \
__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \
"=q" (res):"r" (nr),"m" (*(addr))); \
res;})
#define find_first_zero(addr) ({ \
int __res; \
__asm__("cld\n" \
"1:\tlodsl\n\t" \
"notl %%eax\n\t" \
"bsfl %%eax,%%edx\n\t" \
"jne 2f\n\t" \
"addl $32,%%ecx\n\t" \
"cmpl $8192,%%ecx\n\t" \
"jl 1b\n\t" \
"xorl %%edx,%%edx\n" \
"2:\taddl %%edx,%%ecx" \
:"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \
__res;})
int minix_free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;
unsigned int bit,zone;
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
if (block < sb->s_firstdatazone || block >= sb->s_nzones)
panic("trying to free block not in datazone");
bh = get_hash_table(dev,block);
if (bh) {
if (bh->b_count > 1) {
brelse(bh);
return 0;
}
bh->b_dirt=0;
bh->b_uptodate=0;
if (bh->b_count)
brelse(bh);
}
zone = block - sb->s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
bh = sb->s_zmap[zone];
if (clear_bit(bit,bh->b_data))
printk("free_block (%04x:%d): bit already cleared\n",dev,block);
bh->b_dirt = 1;
return 1;
}
int minix_new_block(int dev)
{
struct buffer_head * bh;
struct super_block * sb;
int i,j;
if (!(sb = get_super(dev)))
panic("trying to get new block from nonexistant device");
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=sb->s_zmap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (i>=8 || !bh || j>=8192)
return 0;
if (set_bit(j,bh->b_data))
panic("new_block: bit already set");
bh->b_dirt = 1;
j += i*8192 + sb->s_firstdatazone-1;
if (j >= sb->s_nzones)
return 0;
if (!(bh=getblk(dev,j)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse(bh);
return j;
}
void minix_free_inode(struct inode * inode)
{
struct buffer_head * bh;
if (!inode)
return;
if (!inode->i_dev) {
memset(inode,0,sizeof(*inode));
return;
}
if (inode->i_count>1) {
printk("free_inode: inode has count=%d\n",inode->i_count);
return;
}
if (inode->i_nlink) {
printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
return;
}
if (!inode->i_sb) {
printk("free_inode: inode on nonexistent device\n");
return;
}
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
if (clear_bit(inode->i_ino&8191,bh->b_data))
printk("free_inode: bit already cleared.\n\r");
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));
}
struct inode * minix_new_inode(int dev)
{
struct inode * inode;
struct buffer_head * bh;
int i,j;
if (!(inode=get_empty_inode()))
return NULL;
if (!(inode->i_sb = get_super(dev))) {
printk("new_inode: unknown device\n");
iput(inode);
return NULL;
}
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=inode->i_sb->s_imap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) {
iput(inode);
return NULL;
}
if (set_bit(j,bh->b_data)) { /* shouldn't happen */
printk("new_inode: bit already set");
iput(inode);
return NULL;
}
bh->b_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
inode->i_dev = dev;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_dirt = 1;
inode->i_ino = j + i*8192;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &minix_inode_operations;
return inode;
}

View File

@@ -0,0 +1,105 @@
/*
* linux/fs/file_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <fcntl.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int read,left,chars,nr;
struct buffer_head * bh;
if (filp->f_pos > inode->i_size)
left = 0;
else
left = inode->i_size - filp->f_pos;
if (left > count)
left = count;
read = 0;
while (left > 0) {
if (nr = bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) {
if (!(bh=bread(inode->i_dev,nr)))
return read?read:-EIO;
} else
bh = NULL;
nr = filp->f_pos & (BLOCK_SIZE-1);
chars = MIN( BLOCK_SIZE-nr , left );
filp->f_pos += chars;
left -= chars;
read += chars;
if (bh) {
char * p = nr + bh->b_data;
while (chars-->0)
put_fs_byte(*(p++),buf++);
brelse(bh);
} else {
while (chars-->0)
put_fs_byte(0,buf++);
}
}
inode->i_atime = CURRENT_TIME;
return read;
}
int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
{
off_t pos;
int written,block,c;
struct buffer_head * bh;
char * p;
/*
* ok, append may not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
*/
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = filp->f_pos;
written = 0;
while (written<count) {
if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
if (!written)
written = -ENOSPC;
break;
}
if (!(bh=bread(inode->i_dev,block))) {
if (!written)
written = -EIO;
break;
}
c = pos % BLOCK_SIZE;
p = c + bh->b_data;
bh->b_dirt = 1;
c = BLOCK_SIZE-c;
if (c > count-written)
c = count-written;
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
written += c;
while (c-->0)
*(p++) = get_fs_byte(buf++);
brelse(bh);
}
inode->i_mtime = CURRENT_TIME;
if (!(filp->f_flags & O_APPEND)) {
filp->f_pos = pos;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
return written;
}

View File

@@ -0,0 +1,145 @@
/*
* linux/fs/minix/inode.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
static int _bmap(struct inode * inode,int block,int create)
{
struct buffer_head * bh;
int i;
if (block<0)
panic("_bmap: block<0");
if (block >= 7+512+512*512)
panic("_bmap: block>big");
if (block<7) {
if (create && !inode->i_data[block])
if (inode->i_data[block]=minix_new_block(inode->i_dev)) {
inode->i_ctime=CURRENT_TIME;
inode->i_dirt=1;
}
return inode->i_data[block];
}
block -= 7;
if (block<512) {
if (create && !inode->i_data[7])
if (inode->i_data[7]=minix_new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_data[7])
return 0;
if (!(bh = bread(inode->i_dev,inode->i_data[7])))
return 0;
i = ((unsigned short *) (bh->b_data))[block];
if (create && !i)
if (i=minix_new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block]=i;
bh->b_dirt=1;
}
brelse(bh);
return i;
}
block -= 512;
if (create && !inode->i_data[8])
if (inode->i_data[8]=minix_new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_data[8])
return 0;
if (!(bh=bread(inode->i_dev,inode->i_data[8])))
return 0;
i = ((unsigned short *)bh->b_data)[block>>9];
if (create && !i)
if (i=minix_new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block>>9]=i;
bh->b_dirt=1;
}
brelse(bh);
if (!i)
return 0;
if (!(bh=bread(inode->i_dev,i)))
return 0;
i = ((unsigned short *)bh->b_data)[block&511];
if (create && !i)
if (i=minix_new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block&511]=i;
bh->b_dirt=1;
}
brelse(bh);
return i;
}
int minix_bmap(struct inode * inode,int block)
{
return _bmap(inode,block,0);
}
int minix_create_block(struct inode * inode, int block)
{
return _bmap(inode,block,1);
}
void minix_read_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
int block;
block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
(inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
raw_inode = ((struct minix_inode *) bh->b_data) +
(inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
inode->i_mode = raw_inode->i_mode;
inode->i_uid = raw_inode->i_uid;
inode->i_gid = raw_inode->i_gid;
inode->i_nlink = raw_inode->i_nlinks;
inode->i_size = raw_inode->i_size;
inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
inode->i_rdev = raw_inode->i_zone[0];
else for (block = 0; block < 9; block++)
inode->i_data[block] = raw_inode->i_zone[block];
brelse(bh);
inode->i_op = &minix_inode_operations;
}
void minix_write_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
int block;
block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
(inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
raw_inode = ((struct minix_inode *)bh->b_data) +
(inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
raw_inode->i_mode = inode->i_mode;
raw_inode->i_uid = inode->i_uid;
raw_inode->i_gid = inode->i_gid;
raw_inode->i_nlinks = inode->i_nlink;
raw_inode->i_size = inode->i_size;
raw_inode->i_time = inode->i_mtime;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = inode->i_rdev;
else for (block = 0; block < 9; block++)
raw_inode->i_zone[block] = inode->i_data[block];
bh->b_dirt=1;
inode->i_dirt=0;
brelse(bh);
}

View File

@@ -0,0 +1,38 @@
/*
* linux/fs/minix/minix_op.c
*
* structures for the minix super_block/inode/file-operations
*/
#include <linux/fs.h>
#include <linux/minix_fs.h>
/*
* These are the low-level inode operations for minix filesystem inodes.
*/
struct inode_operations minix_inode_operations = {
minix_create,
minix_lookup,
minix_link,
minix_unlink,
minix_symlink,
minix_mkdir,
minix_rmdir,
minix_mknod,
minix_rename,
minix_readlink,
minix_open,
minix_release,
minix_follow_link
};
/*
* We have just NULL's here: the current defaults are ok for
* the minix filesystem.
*/
struct file_operations minix_file_operations = {
NULL, /* lseek */
NULL, /* read */
NULL /* write */
};

View File

@@ -0,0 +1,795 @@
/*
* linux/fs/minix/namei.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <const.h>
#include <sys/stat.h>
extern int permission(struct inode * inode,int mask);
extern struct inode * _namei(const char * filename, struct inode * base,
int follow_links);
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
* truncated. Else they will be disallowed.
*/
/* #define NO_TRUNCATE */
/*
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use minix_match. No big problem. Match also makes
* some sanity tests.
*
* NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
*/
static int minix_match(int len,const char * name,struct minix_dir_entry * de)
{
register int same __asm__("ax");
if (!de || !de->inode || len > MINIX_NAME_LEN)
return 0;
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
if (len < MINIX_NAME_LEN && de->name[len])
return 0;
__asm__("cld\n\t"
"fs ; repe ; cmpsb\n\t"
"setz %%al"
:"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
:"cx","di","si");
return same;
}
/*
* minix_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
* itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
static struct buffer_head * minix_find_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
int entries;
int block,i;
struct buffer_head * bh;
struct minix_dir_entry * de;
*res_dir = NULL;
if (!dir)
return NULL;
#ifdef NO_TRUNCATE
if (namelen > MINIX_NAME_LEN)
return NULL;
#else
if (namelen > MINIX_NAME_LEN)
namelen = MINIX_NAME_LEN;
#endif
entries = dir->i_size / (sizeof (struct minix_dir_entry));
if (!(block = dir->i_data[0]))
return NULL;
if (!(bh = bread(dir->i_dev,block)))
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (i < entries) {
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
bh = NULL;
if (!(block = bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) ||
!(bh = bread(dir->i_dev,block))) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
de = (struct minix_dir_entry *) bh->b_data;
}
if (minix_match(namelen,name,de)) {
*res_dir = de;
return bh;
}
de++;
i++;
}
brelse(bh);
return NULL;
}
struct inode * minix_follow_link(struct inode * dir, struct inode * inode)
{
unsigned short fs;
struct buffer_head * bh;
if (!dir) {
dir = current->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
return NULL;
}
if (!S_ISLNK(inode->i_mode)) {
iput(dir);
return inode;
}
__asm__("mov %%fs,%0":"=r" (fs));
if ((current->link_count > 5) || !inode->i_data[0] ||
!(bh = bread(inode->i_dev, inode->i_data[0]))) {
iput(dir);
iput(inode);
return NULL;
}
iput(inode);
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++;
inode = _namei(bh->b_data,dir,1);
current->link_count--;
__asm__("mov %0,%%fs"::"r" (fs));
brelse(bh);
return inode;
}
int minix_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
int ino;
struct minix_dir_entry * de;
struct buffer_head * bh;
*result = NULL;
if (!dir)
return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
if (!(bh = minix_find_entry(dir,name,len,&de))) {
iput(dir);
return -ENOENT;
}
ino = de->inode;
brelse(bh);
if (!(*result = iget(dir->i_dev,ino))) {
iput(dir);
return -EACCES;
}
iput(dir);
return 0;
}
/*
* minix_add_entry()
*
* adds a file entry to the specified directory, using the same
* semantics as minix_find_entry(). It returns NULL if it failed.
*
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
*/
static struct buffer_head * minix_add_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
int block,i;
struct buffer_head * bh;
struct minix_dir_entry * de;
*res_dir = NULL;
if (!dir)
return NULL;
#ifdef NO_TRUNCATE
if (namelen > MINIX_NAME_LEN)
return NULL;
#else
if (namelen > MINIX_NAME_LEN)
namelen = MINIX_NAME_LEN;
#endif
if (!namelen)
return NULL;
if (!(block = dir->i_data[0]))
return NULL;
if (!(bh = bread(dir->i_dev,block)))
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (1) {
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
bh = NULL;
block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK);
if (!block)
return NULL;
if (!(bh = bread(dir->i_dev,block))) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
de = (struct minix_dir_entry *) bh->b_data;
}
if (i*sizeof(struct minix_dir_entry) >= dir->i_size) {
de->inode=0;
dir->i_size = (i+1)*sizeof(struct minix_dir_entry);
dir->i_dirt = 1;
dir->i_ctime = CURRENT_TIME;
}
if (!de->inode) {
dir->i_mtime = CURRENT_TIME;
for (i=0; i < MINIX_NAME_LEN ; i++)
de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
bh->b_dirt = 1;
*res_dir = de;
return bh;
}
de++;
i++;
}
brelse(bh);
return NULL;
}
int minix_create(struct inode * dir,const char * name, int len, int mode,
struct inode ** result)
{
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
*result = NULL;
if (!dir)
return -ENOENT;
inode = minix_new_inode(dir->i_dev);
if (!inode) {
iput(dir);
return -ENOSPC;
}
inode->i_mode = mode;
inode->i_dirt = 1;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
inode->i_nlink--;
iput(inode);
iput(dir);
return -ENOSPC;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
brelse(bh);
iput(dir);
*result = inode;
return 0;
}
int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
{
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
if (!dir)
return -ENOENT;
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
iput(dir);
return -EEXIST;
}
inode = minix_new_inode(dir->i_dev);
if (!inode) {
iput(dir);
return -ENOSPC;
}
inode->i_uid = current->euid;
inode->i_mode = mode;
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
inode->i_mtime = inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
inode->i_nlink--;
iput(inode);
iput(dir);
return -ENOSPC;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
brelse(bh);
iput(dir);
iput(inode);
return 0;
}
int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
{
struct inode * inode;
struct buffer_head * bh, *dir_block;
struct minix_dir_entry * de;
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
iput(dir);
return -EEXIST;
}
inode = minix_new_inode(dir->i_dev);
if (!inode) {
iput(dir);
return -ENOSPC;
}
inode->i_size = 32;
inode->i_dirt = 1;
inode->i_mtime = inode->i_atime = CURRENT_TIME;
if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
iput(dir);
inode->i_nlink--;
iput(inode);
return -ENOSPC;
}
inode->i_dirt = 1;
if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) {
iput(dir);
inode->i_nlink--;
iput(inode);
return -ERROR;
}
de = (struct minix_dir_entry *) dir_block->b_data;
de->inode=inode->i_ino;
strcpy(de->name,".");
de++;
de->inode = dir->i_ino;
strcpy(de->name,"..");
inode->i_nlink = 2;
dir_block->b_dirt = 1;
brelse(dir_block);
inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
inode->i_dirt = 1;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
iput(dir);
inode->i_nlink=0;
iput(inode);
return -ENOSPC;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
dir->i_nlink++;
dir->i_dirt = 1;
iput(dir);
iput(inode);
brelse(bh);
return 0;
}
/*
* routine to check that the specified directory is empty (for rmdir)
*/
static int empty_dir(struct inode * inode)
{
int nr,block;
int len;
struct buffer_head * bh;
struct minix_dir_entry * de;
len = inode->i_size / sizeof (struct minix_dir_entry);
if (len<2 || !inode->i_data[0] ||
!(bh=bread(inode->i_dev,inode->i_data[0]))) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
}
de = (struct minix_dir_entry *) bh->b_data;
if (de[0].inode != inode->i_ino || !de[1].inode ||
strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
}
nr = 2;
de += 2;
while (nr<len) {
if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
brelse(bh);
block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK);
if (!block) {
nr += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
if (!(bh=bread(inode->i_dev,block)))
return 0;
de = (struct minix_dir_entry *) bh->b_data;
}
if (de->inode) {
brelse(bh);
return 0;
}
de++;
nr++;
}
brelse(bh);
return 1;
}
int minix_rmdir(struct inode * dir, const char * name, int len)
{
int retval;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
inode = NULL;
bh = minix_find_entry(dir,name,len,&de);
retval = -ENOENT;
if (!bh)
goto end_rmdir;
retval = -EPERM;
if (!(inode = iget(dir->i_dev, de->inode)))
goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid &&
inode->i_uid != current->euid)
goto end_rmdir;
if (inode->i_dev != dir->i_dev)
goto end_rmdir;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto end_rmdir;
if (!S_ISDIR(inode->i_mode)) {
retval = -ENOTDIR;
goto end_rmdir;
}
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
goto end_rmdir;
}
if (inode->i_count > 1) {
retval = -EBUSY;
goto end_rmdir;
}
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
de->inode = 0;
bh->b_dirt = 1;
inode->i_nlink=0;
inode->i_dirt=1;
dir->i_nlink--;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt=1;
retval = 0;
end_rmdir:
iput(dir);
iput(inode);
brelse(bh);
return retval;
}
int minix_unlink(struct inode * dir, const char * name, int len)
{
int retval;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
retval = -ENOENT;
inode = NULL;
bh = minix_find_entry(dir,name,len,&de);
if (!bh)
goto end_unlink;
if (!(inode = iget(dir->i_dev, de->inode)))
goto end_unlink;
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) && !suser() &&
current->euid != inode->i_uid &&
current->euid != dir->i_uid)
goto end_unlink;
if (S_ISDIR(inode->i_mode))
goto end_unlink;
if (!inode->i_nlink) {
printk("Deleting nonexistent file (%04x:%d), %d\n",
inode->i_dev,inode->i_ino,inode->i_nlink);
inode->i_nlink=1;
}
de->inode = 0;
bh->b_dirt = 1;
inode->i_nlink--;
inode->i_dirt = 1;
inode->i_ctime = CURRENT_TIME;
retval = 0;
end_unlink:
brelse(bh);
iput(inode);
iput(dir);
return retval;
}
int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
{
struct minix_dir_entry * de;
struct inode * inode = NULL;
struct buffer_head * bh = NULL, * name_block = NULL;
int i;
char c;
if (!(inode = minix_new_inode(dir->i_dev))) {
iput(dir);
return -ENOSPC;
}
inode->i_mode = S_IFLNK | 0777;
inode->i_dirt = 1;
if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
iput(dir);
inode->i_nlink--;
iput(inode);
return -ENOSPC;
}
inode->i_dirt = 1;
if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) {
iput(dir);
inode->i_nlink--;
iput(inode);
return -ERROR;
}
i = 0;
while (i < 1023 && (c=get_fs_byte(symname++)))
name_block->b_data[i++] = c;
name_block->b_data[i] = 0;
name_block->b_dirt = 1;
brelse(name_block);
inode->i_size = i;
inode->i_dirt = 1;
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
inode->i_nlink--;
iput(inode);
brelse(bh);
iput(dir);
return -EEXIST;
}
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
inode->i_nlink--;
iput(inode);
iput(dir);
return -ENOSPC;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
brelse(bh);
iput(dir);
iput(inode);
return 0;
}
int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
{
struct minix_dir_entry * de;
struct buffer_head * bh;
if (S_ISDIR(oldinode->i_mode)) {
iput(oldinode);
iput(dir);
return -EPERM;
}
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
iput(dir);
iput(oldinode);
return -EEXIST;
}
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
iput(dir);
iput(oldinode);
return -ENOSPC;
}
de->inode = oldinode->i_ino;
bh->b_dirt = 1;
brelse(bh);
iput(dir);
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
oldinode->i_dirt = 1;
iput(oldinode);
return 0;
}
static int subdir(struct inode * new, struct inode * old)
{
unsigned short fs;
int ino;
int result;
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
new->i_count++;
result = 0;
for (;;) {
if (new == old) {
result = 1;
break;
}
if (new->i_dev != old->i_dev)
break;
ino = new->i_ino;
if (minix_lookup(new,"..",2,&new))
break;
if (new->i_ino == ino)
break;
}
iput(new);
__asm__("mov %0,%%fs"::"r" (fs));
return result;
}
#define PARENT_INO(buffer) \
(((struct minix_dir_entry *) (buffer))[1].inode)
#define PARENT_NAME(buffer) \
(((struct minix_dir_entry *) (buffer))[1].name)
/*
* rename uses retrying to avoid race-conditions: at least they should be minimal.
* it tries to allocate all the blocks, then sanity-checks, and if the sanity-
* checks fail, it tries to restart itself again. Very practical - no changes
* are done until we know everything works ok.. and then all the changes can be
* done in one fell swoop when we have claimed all the buffers needed.
*
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
struct minix_dir_entry * old_de, * new_de;
int retval;
goto start_up;
try_again:
brelse(old_bh);
brelse(new_bh);
brelse(dir_bh);
iput(old_inode);
iput(new_inode);
current->counter = 0;
schedule();
start_up:
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
old_inode = iget(old_dir->i_dev, old_de->inode);
if (!old_inode)
goto end_rename;
new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
if (new_bh) {
new_inode = iget(new_dir->i_dev, new_de->inode);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
}
}
if (new_inode == old_inode) {
retval = 0;
goto end_rename;
}
if (S_ISDIR(old_inode->i_mode)) {
retval = -EEXIST;
if (new_bh)
goto end_rename;
retval = -EACCES;
if (!permission(old_inode, MAY_WRITE))
goto end_rename;
retval = -EINVAL;
if (subdir(new_dir, old_inode))
goto end_rename;
retval = -EIO;
if (!old_inode->i_data[0])
goto end_rename;
if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0])))
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
}
if (!new_bh)
new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
retval = -ENOSPC;
if (!new_bh)
goto end_rename;
/* sanity checking before doing the rename - avoid races */
if (new_inode && (new_de->inode != new_inode->i_ino))
goto try_again;
if (new_de->inode && !new_inode)
goto try_again;
if (old_de->inode != old_inode->i_ino)
goto try_again;
/* ok, that's it */
old_de->inode = 0;
new_de->inode = old_inode->i_ino;
if (new_inode)
new_inode->i_nlink--;
old_bh->b_dirt = 1;
new_bh->b_dirt = 1;
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
dir_bh->b_dirt = 1;
old_dir->i_nlink--;
new_dir->i_nlink++;
old_dir->i_dirt = 1;
new_dir->i_dirt = 1;
}
retval = 0;
end_rename:
brelse(dir_bh);
brelse(old_bh);
brelse(new_bh);
iput(old_inode);
iput(new_inode);
iput(old_dir);
iput(new_dir);
return retval;
}
/*
* Ok, rename also locks out other renames, as they can change the parent of
* a directory, and we don't want any races. Other races are checked for by
* "do_rename()", which restarts if there are inconsistencies.
*
* Note that there is no race between different filesystems: it's only within
* the same device that races occur: many renames can happen at once, as long
* as they are on different partitions.
*/
int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len)
{
static struct task_struct * wait = NULL;
static int lock = 0;
int result;
while (lock)
sleep_on(&wait);
lock = 1;
result = do_minix_rename(old_dir, old_name, old_len,
new_dir, new_name, new_len);
lock = 0;
wake_up(&wait);
return result;
}
int minix_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
int i;
char c;
if (!S_ISLNK(inode->i_mode)) {
iput(inode);
return -EINVAL;
}
if (buflen > 1023)
buflen = 1023;
if (inode->i_data[0])
bh = bread(inode->i_dev, inode->i_data[0]);
else
bh = NULL;
iput(inode);
if (!bh)
return 0;
i = 0;
while (i<buflen && (c = bh->b_data[i])) {
i++;
put_fs_byte(c,buffer++);
}
brelse(bh);
return i;
}

View File

@@ -0,0 +1,154 @@
/*
* linux/fs/truncate.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/tty.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
static int minix_free_ind(int dev,int block)
{
struct buffer_head * bh;
unsigned short * p;
int i;
int block_busy;
if (!block)
return 1;
block_busy = 0;
if (bh=bread(dev,block)) {
p = (unsigned short *) bh->b_data;
for (i=0;i<512;i++,p++)
if (*p)
if (minix_free_block(dev,*p)) {
*p = 0;
bh->b_dirt = 1;
} else
block_busy = 1;
brelse(bh);
}
if (block_busy)
return 0;
else
return minix_free_block(dev,block);
}
static int minix_free_dind(int dev,int block)
{
struct buffer_head * bh;
unsigned short * p;
int i;
int block_busy;
if (!block)
return 1;
block_busy = 0;
if (bh=bread(dev,block)) {
p = (unsigned short *) bh->b_data;
for (i=0;i<512;i++,p++)
if (*p)
if (minix_free_ind(dev,*p)) {
*p = 0;
bh->b_dirt = 1;
} else
block_busy = 1;
brelse(bh);
}
if (block_busy)
return 0;
else
return minix_free_block(dev,block);
}
void minix_truncate(struct inode * inode)
{
int i;
int block_busy;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
repeat:
block_busy = 0;
for (i=0;i<7;i++)
if (inode->i_data[i]) {
if (minix_free_block(inode->i_dev,inode->i_data[i]))
inode->i_data[i]=0;
else
block_busy = 1;
}
if (minix_free_ind(inode->i_dev,inode->i_data[7]))
inode->i_data[7] = 0;
else
block_busy = 1;
if (minix_free_dind(inode->i_dev,inode->i_data[8]))
inode->i_data[8] = 0;
else
block_busy = 1;
inode->i_dirt = 1;
if (block_busy) {
current->counter = 0;
schedule();
goto repeat;
}
inode->i_size = 0;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
/*
* Called when a inode is released. Note that this is different
* from minix_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
void minix_release(struct inode * inode, struct file * filp)
{
printk("minix_release not implemented\n");
}
static int check_char_dev(struct inode * inode, struct file * filp)
{
struct tty_struct *tty;
int min, dev;
dev = inode->i_rdev;
if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
if (MAJOR(dev) == 5)
min = current->tty;
else
min = MINOR(dev);
if (min < 0)
return -1;
if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
return -1;
tty = TTY_TABLE(min);
if (!(filp->f_flags & O_NOCTTY) &&
current->leader &&
current->tty<0 &&
tty->session==0) {
current->tty = min;
tty->session= current->session;
tty->pgrp = current->pgrp;
}
}
return 0;
}
/*
* Called every time a minix-file is opened
*/
int minix_open(struct inode * inode, struct file * filp)
{
if (S_ISCHR(inode->i_mode)) {
if (check_char_dev(inode,filp))
return -EAGAIN;
} else if (S_ISBLK(inode->i_mode))
check_disk_change(inode->i_rdev);
filp->f_op = &minix_file_operations;
return 0;
}

View File

@@ -0,0 +1,460 @@
/*
* linux/fs/namei.c
*
* (C) 1991 Linus Torvalds
*/
/*
* Some corrections by tytso.
*/
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <const.h>
#include <sys/stat.h>
struct inode * _namei(const char * filename, struct inode * base,
int follow_links);
#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
* truncated. Else they will be disallowed.
*/
/* #define NO_TRUNCATE */
/*
* permission()
*
* is used to check for read/write/execute permissions on a file.
* I don't know if we should look at just the euid or both euid and
* uid, but that should be easily changed.
*/
int permission(struct inode * inode,int mask)
{
int mode = inode->i_mode;
/* special case: not even root can read/write a deleted file */
if (inode->i_dev && !inode->i_nlink)
return 0;
else if (current->euid == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
if (((mode & mask & 0007) == mask) || suser())
return 1;
return 0;
}
/*
* lookup() looks up one part of a pathname, using the fs-dependent
* routines (currently minix_lookup) for it. It also checks for
* fathers (pseudo-roots, mount-points)
*/
int lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
struct super_block * sb;
*result = NULL;
if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
if (dir == current->root)
len = 1;
else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
sb = dir->i_sb;
iput(dir);
if (dir = sb->s_covered)
dir->i_count++;
}
}
if (!dir)
return -ENOENT;
if (!permission(dir,MAY_EXEC)) {
iput(dir);
return -EACCES;
}
if (!len) {
*result = dir;
return 0;
}
if (!dir->i_op || !dir->i_op->lookup) {
iput(dir);
return -ENOENT;
}
return dir->i_op->lookup(dir,name,len,result);
}
struct inode * follow_link(struct inode * dir, struct inode * inode)
{
if (!dir || !inode) {
iput(dir);
iput(inode);
return NULL;
}
if (!inode->i_op || !inode->i_op->follow_link) {
iput(dir);
return inode;
}
return inode->i_op->follow_link(dir,inode);
}
/*
* dir_namei()
*
* dir_namei() returns the inode of the directory of the
* specified name, and the name within that directory.
*/
static struct inode * dir_namei(const char * pathname,
int * namelen, const char ** name, struct inode * base)
{
char c;
const char * thisname;
int len,error;
struct inode * inode;
if (!base) {
base = current->pwd;
base->i_count++;
}
if ((c=get_fs_byte(pathname))=='/') {
iput(base);
base = current->root;
pathname++;
base->i_count++;
}
while (1) {
thisname = pathname;
for(len=0;(c=get_fs_byte(pathname++))&&(c!='/');len++)
/* nothing */ ;
if (!c)
break;
base->i_count++;
error = lookup(base,thisname,len,&inode);
if (error) {
iput(base);
return NULL;
}
if (!(base = follow_link(base,inode)))
return NULL;
}
*name = thisname;
*namelen = len;
return base;
}
struct inode * _namei(const char * pathname, struct inode * base,
int follow_links)
{
const char * basename;
int namelen,error;
struct inode * inode;
if (!(base = dir_namei(pathname,&namelen,&basename,base)))
return NULL;
base->i_count++; /* lookup uses up base */
error = lookup(base,basename,namelen,&inode);
if (error) {
iput(base);
return NULL;
}
if (follow_links)
inode = follow_link(base,inode);
else
iput(base);
if (inode) {
inode->i_atime=CURRENT_TIME;
inode->i_dirt=1;
}
return inode;
}
struct inode * lnamei(const char * pathname)
{
return _namei(pathname, NULL, 0);
}
/*
* namei()
*
* is used by most simple commands to get the inode of a specified name.
* Open, link etc use their own routines, but this is enough for things
* like 'chmod' etc.
*/
struct inode * namei(const char * pathname)
{
return _namei(pathname,NULL,1);
}
/*
* open_namei()
*
* namei for open - this is in fact almost the whole open-routine.
*/
int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode)
{
const char * basename;
int namelen,error;
struct inode * dir, *inode;
if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
flag |= O_WRONLY;
mode &= 0777 & ~current->umask;
mode |= I_REGULAR;
if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
return -ENOENT;
if (!namelen) { /* special case: '/usr/' etc */
if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
*res_inode=dir;
return 0;
}
iput(dir);
return -EISDIR;
}
dir->i_count++; /* lookup eats the dir */
error = lookup(dir,basename,namelen,&inode);
if (error) {
if (!(flag & O_CREAT)) {
iput(dir);
return error;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
}
if (!dir->i_op || !dir->i_op->create) {
iput(dir);
return -EACCES;
}
return dir->i_op->create(dir,basename,namelen,mode,res_inode);
}
if (flag & O_EXCL) {
iput(dir);
iput(inode);
return -EEXIST;
}
if (!(inode = follow_link(dir,inode)))
return -ELOOP;
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
!permission(inode,ACC_MODE(flag))) {
iput(inode);
return -EPERM;
}
inode->i_atime = CURRENT_TIME;
if (flag & O_TRUNC)
minix_truncate(inode);
*res_inode = inode;
return 0;
}
int sys_mknod(const char * filename, int mode, int dev)
{
const char * basename;
int namelen;
struct inode * dir;
if (!suser())
return -EPERM;
if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
return -ENOENT;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EPERM;
}
if (!dir->i_op || !dir->i_op->mknod) {
iput(dir);
return -EPERM;
}
return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
int sys_mkdir(const char * pathname, int mode)
{
const char * basename;
int namelen;
struct inode * dir;
if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
return -ENOENT;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EPERM;
}
if (!dir->i_op || !dir->i_op->mkdir) {
iput(dir);
return -EPERM;
}
return dir->i_op->mkdir(dir,basename,namelen,mode);
}
int sys_rmdir(const char * name)
{
const char * basename;
int namelen;
struct inode * dir;
if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
return -ENOENT;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EPERM;
}
if (!dir->i_op || !dir->i_op->rmdir) {
iput(dir);
return -EPERM;
}
return dir->i_op->rmdir(dir,basename,namelen);
}
int sys_unlink(const char * name)
{
const char * basename;
int namelen;
struct inode * dir;
if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
return -ENOENT;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EPERM;
}
if (!dir->i_op || !dir->i_op->unlink) {
iput(dir);
return -EPERM;
}
return dir->i_op->unlink(dir,basename,namelen);
}
int sys_symlink(const char * oldname, const char * newname)
{
struct inode * dir;
const char * basename;
int namelen;
dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir)
return -EACCES;
if (!namelen) {
iput(dir);
return -EPERM;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EPERM;
}
if (!dir->i_op || !dir->i_op->symlink) {
iput(dir);
return -EPERM;
}
return dir->i_op->symlink(dir,basename,namelen,oldname);
}
int sys_link(const char * oldname, const char * newname)
{
struct inode * oldinode, * dir;
const char * basename;
int namelen;
oldinode = namei(oldname);
if (!oldinode)
return -ENOENT;
dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir) {
iput(oldinode);
return -EACCES;
}
if (!namelen) {
iput(oldinode);
iput(dir);
return -EPERM;
}
if (dir->i_dev != oldinode->i_dev) {
iput(dir);
iput(oldinode);
return -EXDEV;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
iput(oldinode);
return -EACCES;
}
if (!dir->i_op || !dir->i_op->link) {
iput(dir);
iput(oldinode);
return -EPERM;
}
return dir->i_op->link(oldinode, dir, basename, namelen);
}
int sys_rename(const char * oldname, const char * newname)
{
struct inode * old_dir, * new_dir;
const char * old_base, * new_base;
int old_len, new_len;
old_dir = dir_namei(oldname,&old_len,&old_base, NULL);
if (!old_dir)
return -ENOENT;
if (!permission(old_dir,MAY_WRITE)) {
iput(old_dir);
return -EACCES;
}
if (!old_len || (get_fs_byte(old_base) == '.' &&
(old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
old_len == 2)))) {
iput(old_dir);
return -EPERM;
}
new_dir = dir_namei(newname,&new_len,&new_base, NULL);
if (!new_dir) {
iput(old_dir);
return -ENOENT;
}
if (!permission(new_dir,MAY_WRITE)) {
iput(old_dir);
iput(new_dir);
return -EACCES;
}
if (!new_len || (get_fs_byte(new_base) == '.' &&
(new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
new_len == 2)))) {
iput(old_dir);
iput(new_dir);
return -EPERM;
}
if (new_dir->i_dev != old_dir->i_dev) {
iput(old_dir);
iput(new_dir);
return -EXDEV;
}
if (!old_dir->i_op || !old_dir->i_op->rename) {
iput(old_dir);
iput(new_dir);
return -EPERM;
}
return old_dir->i_op->rename(old_dir, old_base, old_len,
new_dir, new_base, new_len);
}

View File

@@ -0,0 +1,198 @@
/*
* linux/fs/open.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
int sys_ustat(int dev, struct ustat * ubuf)
{
return -ENOSYS;
}
int sys_utime(char * filename, struct utimbuf * times)
{
struct inode * inode;
long actime,modtime;
if (!(inode=namei(filename)))
return -ENOENT;
if (times) {
actime = get_fs_long((unsigned long *) &times->actime);
modtime = get_fs_long((unsigned long *) &times->modtime);
} else
actime = modtime = CURRENT_TIME;
inode->i_atime = actime;
inode->i_mtime = modtime;
inode->i_dirt = 1;
iput(inode);
return 0;
}
/*
* XXX should we use the real or effective uid? BSD uses the real uid,
* so as to make this call useful to setuid programs.
*/
int sys_access(const char * filename,int mode)
{
struct inode * inode;
int res, i_mode;
mode &= 0007;
if (!(inode=namei(filename)))
return -EACCES;
i_mode = res = inode->i_mode & 0777;
iput(inode);
if (current->uid == inode->i_uid)
res >>= 6;
else if (current->gid == inode->i_gid)
res >>= 6;
if ((res & 0007 & mode) == mode)
return 0;
/*
* XXX we are doing this test last because we really should be
* swapping the effective with the real user id (temporarily),
* and then calling suser() routine. If we do call the
* suser() routine, it needs to be called last.
*/
if ((!current->uid) &&
(!(mode & 1) || (i_mode & 0111)))
return 0;
return -EACCES;
}
int sys_chdir(const char * filename)
{
struct inode * inode;
if (!(inode = namei(filename)))
return -ENOENT;
if (!S_ISDIR(inode->i_mode)) {
iput(inode);
return -ENOTDIR;
}
iput(current->pwd);
current->pwd = inode;
return (0);
}
int sys_chroot(const char * filename)
{
struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
if (!S_ISDIR(inode->i_mode)) {
iput(inode);
return -ENOTDIR;
}
iput(current->root);
current->root = inode;
return (0);
}
int sys_chmod(const char * filename,int mode)
{
struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
if ((current->euid != inode->i_uid) && !suser()) {
iput(inode);
return -EACCES;
}
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
iput(inode);
return 0;
}
int sys_chown(const char * filename,int uid,int gid)
{
struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
if (!suser()) {
iput(inode);
return -EACCES;
}
inode->i_uid=uid;
inode->i_gid=gid;
inode->i_dirt=1;
iput(inode);
return 0;
}
int sys_open(const char * filename,int flag,int mode)
{
struct inode * inode;
struct file * f;
int i,fd;
for(fd=0 ; fd<NR_OPEN ; fd++)
if (!current->filp[fd])
break;
if (fd>=NR_OPEN)
return -EINVAL;
current->close_on_exec &= ~(1<<fd);
f=0+file_table;
for (i=0 ; i<NR_FILE ; i++,f++)
if (!f->f_count) break;
if (i>=NR_FILE)
return -EINVAL;
(current->filp[fd]=f)->f_count++;
if ((i=open_namei(filename,flag,mode,&inode))<0) {
current->filp[fd]=NULL;
f->f_count=0;
return i;
}
f->f_op = NULL;
f->f_mode = "\001\002\003\000"[flag & O_ACCMODE];
f->f_flags = flag;
f->f_count = 1;
f->f_inode = inode;
f->f_pos = 0;
if (inode->i_op && inode->i_op->open)
if (i = inode->i_op->open(inode,f)) {
iput(inode);
f->f_count=0;
current->filp[fd]=NULL;
return i;
}
return (fd);
}
int sys_creat(const char * pathname, int mode)
{
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
int sys_close(unsigned int fd)
{
struct file * filp;
if (fd >= NR_OPEN)
return -EINVAL;
current->close_on_exec &= ~(1<<fd);
if (!(filp = current->filp[fd]))
return -EINVAL;
current->filp[fd] = NULL;
if (filp->f_count == 0)
panic("Close: file count is 0");
if (--filp->f_count)
return (0);
iput(filp->f_inode);
return (0);
}

View File

@@ -0,0 +1,131 @@
/*
* linux/fs/pipe.c
*
* (C) 1991 Linus Torvalds
*/
#include <signal.h>
#include <errno.h>
#include <termios.h>
#include <fcntl.h>
#include <linux/sched.h>
#include <asm/segment.h>
#include <linux/kernel.h>
int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int chars, size, read = 0;
if (!(filp->f_flags & O_NONBLOCK))
while (!PIPE_SIZE(*inode)) {
wake_up(& PIPE_WRITE_WAIT(*inode));
if (inode->i_count != 2) /* are there any writers? */
return 0;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
interruptible_sleep_on(& PIPE_READ_WAIT(*inode));
}
while (count>0 && (size = PIPE_SIZE(*inode))) {
chars = PAGE_SIZE-PIPE_TAIL(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
count -= chars;
read += chars;
size = PIPE_TAIL(*inode);
PIPE_TAIL(*inode) += chars;
PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
while (chars-->0)
put_fs_byte(((char *)inode->i_size)[size++],buf++);
}
wake_up(& PIPE_WRITE_WAIT(*inode));
return read;
}
int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
{
int chars, size, written = 0;
while (count>0) {
while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
wake_up(& PIPE_READ_WAIT(*inode));
if (inode->i_count != 2) { /* no readers */
current->signal |= (1<<(SIGPIPE-1));
return written?written:-EINTR;
}
if (current->signal & ~current->blocked)
return written?written:-EINTR;
interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
}
chars = PAGE_SIZE-PIPE_HEAD(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
count -= chars;
written += chars;
size = PIPE_HEAD(*inode);
PIPE_HEAD(*inode) += chars;
PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
while (chars-->0)
((char *)inode->i_size)[size++]=get_fs_byte(buf++);
}
wake_up(& PIPE_READ_WAIT(*inode));
return written;
}
int sys_pipe(unsigned long * fildes)
{
struct inode * inode;
struct file * f[2];
int fd[2];
int i,j;
j=0;
for(i=0;j<2 && i<NR_FILE;i++)
if (!file_table[i].f_count)
(f[j++]=i+file_table)->f_count++;
if (j==1)
f[0]->f_count=0;
if (j<2)
return -1;
j=0;
for(i=0;j<2 && i<NR_OPEN;i++)
if (!current->filp[i]) {
current->filp[ fd[j]=i ] = f[j];
j++;
}
if (j==1)
current->filp[fd[0]]=NULL;
if (j<2) {
f[0]->f_count=f[1]->f_count=0;
return -1;
}
if (!(inode=get_pipe_inode())) {
current->filp[fd[0]] =
current->filp[fd[1]] = NULL;
f[0]->f_count = f[1]->f_count = 0;
return -1;
}
f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0;
f[0]->f_mode = 1; /* read */
f[1]->f_mode = 2; /* write */
put_fs_long(fd[0],0+fildes);
put_fs_long(fd[1],1+fildes);
return 0;
}
int pipe_ioctl(struct inode *pino, int cmd, int arg)
{
switch (cmd) {
case FIONREAD:
verify_area((void *) arg,4);
put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
return 0;
default:
return -EINVAL;
}
}

View File

@@ -0,0 +1,97 @@
/*
* linux/fs/read_write.c
*
* (C) 1991 Linus Torvalds
*/
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/segment.h>
int sys_lseek(unsigned int fd,off_t offset, unsigned int origin)
{
struct file * file;
int tmp;
if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode))
return -EBADF;
if (origin > 2)
return -EINVAL;
if (file->f_inode->i_pipe)
return -ESPIPE;
if (file->f_op && file->f_op->lseek)
return file->f_op->lseek(file->f_inode,file,offset,origin);
/* this is the default handler if no lseek handler is present */
switch (origin) {
case 0:
if (offset<0) return -EINVAL;
file->f_pos=offset;
break;
case 1:
if (file->f_pos+offset<0) return -EINVAL;
file->f_pos += offset;
break;
case 2:
if ((tmp=file->f_inode->i_size+offset) < 0)
return -EINVAL;
file->f_pos = tmp;
}
return file->f_pos;
}
int sys_read(unsigned int fd,char * buf,unsigned int count)
{
struct file * file;
struct inode * inode;
if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode))
return -EBADF;
if (!(file->f_mode & 1))
return -EBADF;
if (!count)
return 0;
verify_area(buf,count);
if (file->f_op && file->f_op->read)
return file->f_op->read(inode,file,buf,count);
/* these are the default read-functions */
if (inode->i_pipe)
return pipe_read(inode,file,buf,count);
if (S_ISCHR(inode->i_mode))
return char_read(inode,file,buf,count);
if (S_ISBLK(inode->i_mode))
return block_read(inode,file,buf,count);
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode))
return minix_file_read(inode,file,buf,count);
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
int sys_write(unsigned int fd,char * buf,unsigned int count)
{
struct file * file;
struct inode * inode;
if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode))
return -EBADF;
if (!(file->f_mode&2))
return -EBADF;
if (!count)
return 0;
if (file->f_op && file->f_op->write)
return file->f_op->write(inode,file,buf,count);
/* these are the default read-functions */
if (inode->i_pipe)
return pipe_write(inode,file,buf,count);
if (S_ISCHR(inode->i_mode))
return char_write(inode,file,buf,count);
if (S_ISBLK(inode->i_mode))
return block_write(inode,file,buf,count);
if (S_ISREG(inode->i_mode))
return minix_file_write(inode,file,buf,count);
printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}

View File

@@ -0,0 +1,282 @@
/*
* This file contains the procedures for the handling of select
*
* Created for Linux based loosely upon Mathius Lattner's minix
* patches by Peter MacDonald. Heavily edited by Linus.
*/
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <const.h>
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
/*
* Ok, Peter made a complicated, but straightforward multiple_wait() function.
* I have rewritten this, taking some shortcuts: This code may not be easy to
* follow, but it should be free of race-conditions, and it's practical. If you
* understand what I'm doing here, then you understand how the linux sleep/wakeup
* mechanism works.
*
* Two very simple procedures, add_wait() and free_wait() make all the work. We
* have to have interrupts disabled throughout the select, but that's not really
* such a loss: sleeping automatically frees interrupts when we aren't in this
* task.
*/
typedef struct {
struct task_struct * old_task;
struct task_struct ** wait_address;
} wait_entry;
typedef struct {
int nr;
wait_entry entry[NR_OPEN*3];
} select_table;
static void add_wait(struct task_struct ** wait_address, select_table * p)
{
int i;
if (!wait_address)
return;
for (i = 0 ; i < p->nr ; i++)
if (p->entry[i].wait_address == wait_address)
return;
p->entry[p->nr].wait_address = wait_address;
p->entry[p->nr].old_task = * wait_address;
*wait_address = current;
p->nr++;
}
static void free_wait(select_table * p)
{
int i;
struct task_struct ** tpp;
for (i = 0; i < p->nr ; i++) {
tpp = p->entry[i].wait_address;
while (*tpp && *tpp != current) {
(*tpp)->state = 0;
current->state = TASK_UNINTERRUPTIBLE;
schedule();
}
if (!*tpp)
printk("free_wait: NULL");
if (*tpp = p->entry[i].old_task)
(**tpp).state = 0;
}
p->nr = 0;
}
static struct tty_struct * get_tty(struct inode * inode)
{
int major, minor;
if (!S_ISCHR(inode->i_mode))
return NULL;
if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4)
return NULL;
if (major == 5)
minor = current->tty;
else
minor = MINOR(inode->i_rdev);
if (minor < 0)
return NULL;
return TTY_TABLE(minor);
}
/*
* The check_XX functions check out a file. We know it's either
* a pipe, a character device or a fifo (fifo's not implemented)
*/
static int check_in(select_table * wait, struct inode * inode)
{
struct tty_struct * tty;
if (tty = get_tty(inode))
if (!EMPTY(tty->secondary))
return 1;
else
add_wait(&tty->secondary->proc_list, wait);
else if (inode->i_pipe)
if (!PIPE_EMPTY(*inode) || inode->i_count < 2)
return 1;
else
add_wait(&inode->i_wait, wait);
return 0;
}
static int check_out(select_table * wait, struct inode * inode)
{
struct tty_struct * tty;
if (tty = get_tty(inode))
if (!FULL(tty->write_q))
return 1;
else
add_wait(&tty->write_q->proc_list, wait);
else if (inode->i_pipe)
if (!PIPE_FULL(*inode))
return 1;
else
add_wait(&inode->i_wait, wait);
return 0;
}
static int check_ex(select_table * wait, struct inode * inode)
{
struct tty_struct * tty;
if (tty = get_tty(inode))
if (!FULL(tty->write_q))
return 0;
else
return 0;
else if (inode->i_pipe)
if (inode->i_count < 2)
return 1;
else
add_wait(&inode->i_wait,wait);
return 0;
}
int do_select(fd_set in, fd_set out, fd_set ex,
fd_set *inp, fd_set *outp, fd_set *exp)
{
int count;
select_table wait_table;
int i;
fd_set mask;
mask = in | out | ex;
for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
if (!(mask & 1))
continue;
if (!current->filp[i])
return -EBADF;
if (!current->filp[i]->f_inode)
return -EBADF;
if (current->filp[i]->f_inode->i_pipe)
continue;
if (S_ISCHR(current->filp[i]->f_inode->i_mode))
continue;
if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
continue;
return -EBADF;
}
repeat:
wait_table.nr = 0;
*inp = *outp = *exp = 0;
count = 0;
mask = 1;
for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
if (mask & in)
if (check_in(&wait_table,current->filp[i]->f_inode)) {
*inp |= mask;
count++;
}
if (mask & out)
if (check_out(&wait_table,current->filp[i]->f_inode)) {
*outp |= mask;
count++;
}
if (mask & ex)
if (check_ex(&wait_table,current->filp[i]->f_inode)) {
*exp |= mask;
count++;
}
}
if (!(current->signal & ~current->blocked) &&
current->timeout && !count) {
current->state = TASK_INTERRUPTIBLE;
schedule();
free_wait(&wait_table);
goto repeat;
}
free_wait(&wait_table);
return count;
}
/*
* Note that we cannot return -ERESTARTSYS, as we change our input
* parameters. Sad, but there you are. We could do some tweaking in
* the library function ...
*/
int sys_select( unsigned long *buffer )
{
/* Perform the select(nd, in, out, ex, tv) system call. */
int i;
fd_set res_in, in = 0, *inp;
fd_set res_out, out = 0, *outp;
fd_set res_ex, ex = 0, *exp;
fd_set mask;
struct timeval *tvp;
unsigned long timeout;
mask = get_fs_long(buffer++);
if (mask >= 32)
mask = ~0;
else
mask = ~((~0) << mask);
inp = (fd_set *) get_fs_long(buffer++);
outp = (fd_set *) get_fs_long(buffer++);
exp = (fd_set *) get_fs_long(buffer++);
tvp = (struct timeval *) get_fs_long(buffer);
if (inp)
in = mask & get_fs_long(inp);
if (outp)
out = mask & get_fs_long(outp);
if (exp)
ex = mask & get_fs_long(exp);
timeout = 0xffffffff;
if (tvp) {
timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
timeout += jiffies;
}
current->timeout = timeout;
cli();
i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
if (current->timeout > jiffies)
timeout = current->timeout - jiffies;
else
timeout = 0;
sti();
current->timeout = 0;
if (i < 0)
return i;
if (inp) {
verify_area(inp, 4);
put_fs_long(res_in,inp);
}
if (outp) {
verify_area(outp,4);
put_fs_long(res_out,outp);
}
if (exp) {
verify_area(exp,4);
put_fs_long(res_ex,exp);
}
if (tvp) {
verify_area(tvp, sizeof(*tvp));
put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
timeout %= HZ;
timeout *= (1000000/HZ);
put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
}
if (!i && (current->signal & ~current->blocked))
return -EINTR;
return i;
}

View File

@@ -0,0 +1,83 @@
/*
* linux/fs/stat.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <sys/stat.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
static void cp_stat(struct inode * inode, struct stat * statbuf)
{
struct stat tmp;
int i;
verify_area(statbuf,sizeof (struct stat));
tmp.st_dev = inode->i_dev;
tmp.st_ino = inode->i_ino;
tmp.st_mode = inode->i_mode;
tmp.st_nlink = inode->i_nlink;
tmp.st_uid = inode->i_uid;
tmp.st_gid = inode->i_gid;
tmp.st_rdev = inode->i_rdev;
tmp.st_size = inode->i_size;
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
tmp.st_ctime = inode->i_ctime;
for (i=0 ; i<sizeof (tmp) ; i++)
put_fs_byte(((char *) &tmp)[i],i + (char *) statbuf);
}
int sys_stat(char * filename, struct stat * statbuf)
{
struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
cp_stat(inode,statbuf);
iput(inode);
return 0;
}
int sys_lstat(char * filename, struct stat * statbuf)
{
struct inode * inode;
if (!(inode = lnamei(filename)))
return -ENOENT;
cp_stat(inode,statbuf);
iput(inode);
return 0;
}
int sys_fstat(unsigned int fd, struct stat * statbuf)
{
struct file * f;
struct inode * inode;
if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
return -EBADF;
cp_stat(inode,statbuf);
return 0;
}
int sys_readlink(const char * path, char * buf, int bufsiz)
{
struct inode * inode;
if (bufsiz <= 0)
return -EINVAL;
verify_area(buf,bufsiz);
if (!(inode = lnamei(path)))
return -ENOENT;
if (!inode->i_op || !inode->i_op->readlink) {
iput(inode);
return -EINVAL;
}
return inode->i_op->readlink(inode,buf,bufsiz);
}

View File

@@ -0,0 +1,288 @@
/*
* linux/fs/super.c
*
* (C) 1991 Linus Torvalds
*/
/*
* super.c contains code to handle the super-block tables.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <errno.h>
#include <sys/stat.h>
int sync_dev(int dev);
void wait_for_keypress(void);
/* set_bit uses setb, as gas doesn't recognize setc */
#define set_bit(bitnr,addr) ({ \
register int __res __asm__("ax"); \
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })
struct super_block super_block[NR_SUPER];
/* this is initialized in init/main.c */
int ROOT_DEV = 0;
static void lock_super(struct super_block * sb)
{
cli();
while (sb->s_lock)
sleep_on(&(sb->s_wait));
sb->s_lock = 1;
sti();
}
static void free_super(struct super_block * sb)
{
cli();
sb->s_lock = 0;
wake_up(&(sb->s_wait));
sti();
}
static void wait_on_super(struct super_block * sb)
{
cli();
while (sb->s_lock)
sleep_on(&(sb->s_wait));
sti();
}
struct super_block * get_super(int dev)
{
struct super_block * s;
if (!dev)
return NULL;
s = 0+super_block;
while (s < NR_SUPER+super_block)
if (s->s_dev == dev) {
wait_on_super(s);
if (s->s_dev == dev)
return s;
s = 0+super_block;
} else
s++;
return NULL;
}
void put_super(int dev)
{
struct super_block * sb;
int i;
if (dev == ROOT_DEV) {
printk("root diskette changed: prepare for armageddon\n\r");
return;
}
if (!(sb = get_super(dev)))
return;
if (sb->s_covered) {
printk("Mounted disk changed - tssk, tssk\n\r");
return;
}
lock_super(sb);
sb->s_dev = 0;
for(i=0;i<MINIX_I_MAP_SLOTS;i++)
brelse(sb->s_imap[i]);
for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(sb->s_zmap[i]);
free_super(sb);
return;
}
static struct super_block * read_super(int dev)
{
struct super_block * s;
struct buffer_head * bh;
int i,block;
if (!dev)
return NULL;
check_disk_change(dev);
if (s = get_super(dev))
return s;
for (s = 0+super_block ;; s++) {
if (s >= NR_SUPER+super_block)
return NULL;
if (!s->s_dev)
break;
}
s->s_dev = dev;
s->s_mounted = NULL;
s->s_covered = NULL;
s->s_time = 0;
s->s_rd_only = 0;
s->s_dirt = 0;
lock_super(s);
if (!(bh = bread(dev,1))) {
s->s_dev=0;
free_super(s);
return NULL;
}
*((struct minix_super_block *) s) =
*((struct minix_super_block *) bh->b_data);
brelse(bh);
if (s->s_magic != MINIX_SUPER_MAGIC) {
s->s_dev = 0;
free_super(s);
return NULL;
}
for (i=0;i < MINIX_I_MAP_SLOTS;i++)
s->s_imap[i] = NULL;
for (i=0;i < MINIX_Z_MAP_SLOTS;i++)
s->s_zmap[i] = NULL;
block=2;
for (i=0 ; i < s->s_imap_blocks ; i++)
if (s->s_imap[i]=bread(dev,block))
block++;
else
break;
for (i=0 ; i < s->s_zmap_blocks ; i++)
if (s->s_zmap[i]=bread(dev,block))
block++;
else
break;
if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
for(i=0;i<MINIX_I_MAP_SLOTS;i++)
brelse(s->s_imap[i]);
for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(s->s_zmap[i]);
s->s_dev=0;
free_super(s);
return NULL;
}
s->s_imap[0]->b_data[0] |= 1;
s->s_zmap[0]->b_data[0] |= 1;
free_super(s);
return s;
}
int sys_umount(char * dev_name)
{
struct inode * inode;
struct super_block * sb;
int dev;
if (!(inode=namei(dev_name)))
return -ENOENT;
dev = inode->i_rdev;
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return -ENOTBLK;
}
iput(inode);
if (dev==ROOT_DEV)
return -EBUSY;
if (!(sb=get_super(dev)) || !(sb->s_covered))
return -ENOENT;
if (!sb->s_covered->i_mount)
printk("Mounted inode has i_mount=0\n");
for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
if (inode->i_dev==dev && inode->i_count)
if (inode == sb->s_mounted && inode->i_count == 1)
continue;
else
return -EBUSY;
sb->s_covered->i_mount=0;
iput(sb->s_covered);
sb->s_covered = NULL;
iput(sb->s_mounted);
sb->s_mounted = NULL;
put_super(dev);
sync_dev(dev);
return 0;
}
int sys_mount(char * dev_name, char * dir_name, int rw_flag)
{
struct inode * dev_i, * dir_i;
struct super_block * sb;
int dev;
if (!(dev_i=namei(dev_name)))
return -ENOENT;
dev = dev_i->i_rdev;
if (!S_ISBLK(dev_i->i_mode)) {
iput(dev_i);
return -EPERM;
}
iput(dev_i);
if (!(dir_i=namei(dir_name)))
return -ENOENT;
if (dir_i->i_count != 1 || dir_i->i_ino == MINIX_ROOT_INO) {
iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) {
iput(dir_i);
return -EPERM;
}
if (!(sb=read_super(dev))) {
iput(dir_i);
return -EBUSY;
}
if (sb->s_covered) {
iput(dir_i);
return -EBUSY;
}
if (dir_i->i_mount) {
iput(dir_i);
return -EPERM;
}
if (!(sb->s_mounted = iget(dev,MINIX_ROOT_INO))) {
iput(dir_i);
return -EPERM;
}
sb->s_covered=dir_i;
dir_i->i_mount=1;
dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */
return 0; /* we do that in umount */
}
void mount_root(void)
{
int i,free;
struct super_block * p;
struct inode * mi;
if (32 != sizeof (struct minix_inode))
panic("bad i-node size");
for(i=0;i<NR_FILE;i++)
file_table[i].f_count=0;
if (MAJOR(ROOT_DEV) == 2) {
printk("Insert root floppy and press ENTER");
wait_for_keypress();
}
for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
p->s_dev = 0;
p->s_lock = 0;
p->s_wait = NULL;
}
if (!(p=read_super(ROOT_DEV)))
panic("Unable to mount root");
if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO)))
panic("Unable to read root i-node");
mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
p->s_mounted = p->s_covered = mi;
current->pwd = mi;
current->root = mi;
free=0;
i=p->s_nzones;
while (-- i >= 0)
if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
free++;
printk("%d/%d free blocks\n\r",free,p->s_nzones);
free=0;
i=p->s_ninodes+1;
while (-- i >= 0)
if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
free++;
printk("%d/%d free inodes\n\r",free,p->s_ninodes);
}