1.6 lseek, read und write

/* Ausschnitte aus /usr/src/linux/fs/read_write.c (Kernel 2.2.5) */
asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
			  unsigned long offset_low, loff_t * result,
			  unsigned int origin)
{
	int retval;
	struct file * file;
	struct dentry * dentry;
	struct inode * inode;
	loff_t offset;

	lock_kernel();
	retval = -EBADF;
	file = fget(fd);                                /*Filepointer holen*/
	if (!file)
		goto bad;
	/* N.B. Shouldn't this be ENOENT?? */
	if (!(dentry = file->f_dentry) ||
	    !(inode = dentry->d_inode))
		goto out_putf;
	retval = -EINVAL;                              /*falsche Zahl übergeben*/
	if (origin > 2)
		goto out_putf;

	offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
			origin);                        /*llseek*/

	retval = (int)offset;
	if (offset >= 0) {
		retval = -EFAULT;
		if (!copy_to_user(result, &offset, sizeof(offset)))
			retval = 0;                     /*Rückgabe*/
	}
out_putf:
	fput(file);
bad:
	unlock_kernel();
	return retval;
}

static inline loff_t llseek(struct file *file, loff_t offset, int origin)
{
	loff_t (*fn)(struct file *, loff_t, int);

	fn = default_llseek;                    /*default_llseek*/
	if (file->f_op && file->f_op->llseek)   /*lssek von spez. FS oder von VFS*/ 
		fn = file->f_op->llseek;
	return fn(file, offset, origin);
}

static loff_t default_llseek(struct file *file, loff_t offset, int origin)
{                                       /*loff_t: 64 Bit-Datei-Positionstyp*/
	long long retval;

	switch (origin) {                               /*berechnen*/
		case 2:
			offset += file->f_dentry->d_inode->i_size;
			break;
		case 1:
			offset += file->f_pos;
	}
	retval = -EINVAL;
	if (offset >= 0) {
		if (offset != file->f_pos) {            /*setzen der*/
			file->f_pos = offset;           /*neuen Position*/
			file->f_reada = 0;
			file->f_version = ++event;
		}
		retval = offset;
	}
	return retval;
}

asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
{
	ssize_t ret;
	struct file * file;
	ssize_t (*read)(struct file *, char *, size_t, loff_t *);

	lock_kernel();                          /*Kernel lock*/

	ret = -EBADF;
	file = fget(fd);                        /*Filepointer aus Filenr.*/
	if (!file)
		goto bad_file;
	if (!(file->f_mode & FMODE_READ))       /*Leserechte ? */
		goto out;
	ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
				file, file->f_pos, count); /*lock for read*/
	if (ret)
		goto out;
	ret = -EINVAL;
	if (!file->f_op || !(read = file->f_op->read))  /*Zeiger read auf
							  f_op read*/
		goto out;
	ret = read(file, buf, count, &file->f_pos);     /*Buffer füllen*/
out:
	fput(file);                             /*File-Pointer freigeben*/
bad_file:
	unlock_kernel();                        /*Kernel unlock*/
	return ret;
}

asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t
count)
{                                                       /*fast wie sys_read*/
	ssize_t ret;
	struct file * file;
	struct inode * inode;
	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);

	lock_kernel();

	ret = -EBADF;
	file = fget(fd);
	if (!file)
		goto bad_file;
	if (!(file->f_mode & FMODE_WRITE))
		goto out;
	inode = file->f_dentry->d_inode;
	ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
				file->f_pos, count);
	if (ret)
		goto out;
	ret = -EINVAL;
	if (!file->f_op || !(write = file->f_op->write))
		goto out;

	down(&inode->i_sem);
	ret = write(file, buf, count, &file->f_pos);	/*Puffer in Datei schreiben*/
	up(&inode->i_sem);                              
out:
	fput(file);
bad_file:
	unlock_kernel();
	return ret;
}
    
Zurück Weiter Inhalt