add directory kernel
This commit is contained in:
118
kernel/0.95/linux-0.95/fs/Makefile
Normal file
118
kernel/0.95/linux-0.95/fs/Makefile
Normal 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
|
||||
93
kernel/0.95/linux-0.95/fs/block_dev.c
Normal file
93
kernel/0.95/linux-0.95/fs/block_dev.c
Normal 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;
|
||||
}
|
||||
426
kernel/0.95/linux-0.95/fs/buffer.c
Normal file
426
kernel/0.95/linux-0.95/fs/buffer.c
Normal 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;
|
||||
}
|
||||
136
kernel/0.95/linux-0.95/fs/char_dev.c
Normal file
136
kernel/0.95/linux-0.95/fs/char_dev.c
Normal 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);
|
||||
}
|
||||
390
kernel/0.95/linux-0.95/fs/exec.c
Normal file
390
kernel/0.95/linux-0.95/fs/exec.c
Normal 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);
|
||||
}
|
||||
77
kernel/0.95/linux-0.95/fs/fcntl.c
Normal file
77
kernel/0.95/linux-0.95/fs/fcntl.c
Normal 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;
|
||||
}
|
||||
}
|
||||
9
kernel/0.95/linux-0.95/fs/file_table.c
Normal file
9
kernel/0.95/linux-0.95/fs/file_table.c
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* linux/fs/file_table.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
struct file file_table[NR_FILE];
|
||||
246
kernel/0.95/linux-0.95/fs/inode.c
Normal file
246
kernel/0.95/linux-0.95/fs/inode.c
Normal 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;
|
||||
}
|
||||
49
kernel/0.95/linux-0.95/fs/ioctl.c
Normal file
49
kernel/0.95/linux-0.95/fs/ioctl.c
Normal 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);
|
||||
}
|
||||
69
kernel/0.95/linux-0.95/fs/minix/Makefile
Normal file
69
kernel/0.95/linux-0.95/fs/minix/Makefile
Normal 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
|
||||
184
kernel/0.95/linux-0.95/fs/minix/bitmap.c
Normal file
184
kernel/0.95/linux-0.95/fs/minix/bitmap.c
Normal 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;
|
||||
}
|
||||
105
kernel/0.95/linux-0.95/fs/minix/file_dev.c
Normal file
105
kernel/0.95/linux-0.95/fs/minix/file_dev.c
Normal 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;
|
||||
}
|
||||
145
kernel/0.95/linux-0.95/fs/minix/inode.c
Normal file
145
kernel/0.95/linux-0.95/fs/minix/inode.c
Normal 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);
|
||||
}
|
||||
38
kernel/0.95/linux-0.95/fs/minix/minix_op.c
Normal file
38
kernel/0.95/linux-0.95/fs/minix/minix_op.c
Normal 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 */
|
||||
};
|
||||
|
||||
795
kernel/0.95/linux-0.95/fs/minix/namei.c
Normal file
795
kernel/0.95/linux-0.95/fs/minix/namei.c
Normal 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;
|
||||
}
|
||||
154
kernel/0.95/linux-0.95/fs/minix/truncate.c
Normal file
154
kernel/0.95/linux-0.95/fs/minix/truncate.c
Normal 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;
|
||||
}
|
||||
460
kernel/0.95/linux-0.95/fs/namei.c
Normal file
460
kernel/0.95/linux-0.95/fs/namei.c
Normal 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);
|
||||
}
|
||||
198
kernel/0.95/linux-0.95/fs/open.c
Normal file
198
kernel/0.95/linux-0.95/fs/open.c
Normal 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 *) ×->actime);
|
||||
modtime = get_fs_long((unsigned long *) ×->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);
|
||||
}
|
||||
131
kernel/0.95/linux-0.95/fs/pipe.c
Normal file
131
kernel/0.95/linux-0.95/fs/pipe.c
Normal 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;
|
||||
}
|
||||
}
|
||||
97
kernel/0.95/linux-0.95/fs/read_write.c
Normal file
97
kernel/0.95/linux-0.95/fs/read_write.c
Normal 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;
|
||||
}
|
||||
282
kernel/0.95/linux-0.95/fs/select.c
Normal file
282
kernel/0.95/linux-0.95/fs/select.c
Normal 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;
|
||||
}
|
||||
83
kernel/0.95/linux-0.95/fs/stat.c
Normal file
83
kernel/0.95/linux-0.95/fs/stat.c
Normal 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);
|
||||
}
|
||||
288
kernel/0.95/linux-0.95/fs/super.c
Normal file
288
kernel/0.95/linux-0.95/fs/super.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user