/*
* linux/fs/read_write.c
*
* (C) 1991 Linus Torvalds
*/

#include <sys/stat.h>		// ļ״̬ͷļļļϵͳ״̬ṹstat{}ͳ
#include <errno.h>		// ͷļϵͳиֳš(Linus minix )
#include <sys/types.h>		// ͷļ˻ϵͳ͡

#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣
#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <asm/segment.h>	// βͷļйضμĴǶʽຯ

// ַ豸д
extern int rw_char (int rw, int dev, char *buf, int count, off_t * pos);
// ܵ
extern int read_pipe (struct m_inode *inode, char *buf, int count);
// дܵ
extern int write_pipe (struct m_inode *inode, char *buf, int count);
// 豸
extern int block_read (int dev, off_t * pos, char *buf, int count);
// 豸д
extern int block_write (int dev, off_t * pos, char *buf, int count);
// ļ
extern int file_read (struct m_inode *inode, struct file *filp,
		      char *buf, int count);
// дļ
extern int file_write (struct m_inode *inode, struct file *filp,
		       char *buf, int count);

//// ضλļдָϵͳú
// fd ļoffset µļдָƫֵorigin ƫƵʼλãSEEK_SET
// (0ļʼ)SEEK_CUR(1ӵǰдλ)SEEK_END(2ļβ)֮һ
int
sys_lseek (unsigned int fd, off_t offset, int origin)
{
  struct file *file;
  int tmp;

// ļֵڳļNR_OPEN(20)߸þļṹָΪգ
// Ӧļṹi ڵֶΪգָ豸ļָǲɶλģ򷵻س벢˳
  if (fd >= NR_OPEN || !(file = current->filp[fd]) || !(file->f_inode)
      || !IS_SEEKABLE (MAJOR (file->f_inode->i_dev)))
    return -EBADF;
// ļӦi ڵǹܵڵ㣬򷵻س룬˳ܵͷβָ벻ƶ
  if (file->f_inode->i_pipe)
    return -ESPIPE;
// õĶλ־ֱ¶λļдָ롣
  switch (origin)
    {
// origin = SEEK_SETҪļʼΪԭļдָ롣ƫֵС㣬
// ش롣ļдָoffset
    case 0:
      if (offset < 0)
	return -EINVAL;
      file->f_pos = offset;
      break;
// origin = SEEK_CURҪļǰдָ봦Ϊԭضλдָ롣ļǰָ
// ƫֵС0򷵻س˳ڵǰдָϼƫֵ
    case 1:
      if (file->f_pos + offset < 0)
	return -EINVAL;
      file->f_pos += offset;
      break;
// origin = SEEK_ENDҪļĩβΪԭضλдָ롣ʱļСƫֵС
// 򷵻س˳ضλдָΪļȼƫֵ
    case 2:
      if ((tmp = file->f_inode->i_size + offset) < 0)
	return -EINVAL;
      file->f_pos = tmp;
      break;
// origin óس˳
    default:
      return -EINVAL;
    }
  return file->f_pos;		// ضλļдֵָ
}

//// ļϵͳú
// fd ļbuf ǻcount ֽ
int
sys_read (unsigned int fd, char *buf, int count)
{
  struct file *file;
  struct m_inode *inode;

// ļֵڳļNR_OPENҪȡֽڼֵС0߸þ
// ļṹָΪգ򷵻س벢˳
  if (fd >= NR_OPEN || count < 0 || !(file = current->filp[fd]))
    return -EINVAL;
// ȡֽcount 0򷵻0˳
  if (!count)
    return 0;
// ֤ݵĻڴơ
  verify_area (buf, count);
// ȡļӦi ڵ㡣ǹܵļǶܵļģʽжܵɹ򷵻
// ȡֽ򷵻س룬˳
  inode = file->f_inode;
  if (inode->i_pipe)
    return (file->f_mode & 1) ? read_pipe (inode, buf, count) : -EIO;
// ַļжַ豸ضȡַ
  if (S_ISCHR (inode->i_mode))
    return rw_char (READ, inode->i_zone[0], buf, count, &file->f_pos);
// ǿ豸ļִп豸ضȡֽ
  if (S_ISBLK (inode->i_mode))
    return block_read (inode->i_zone[0], &file->f_pos, buf, count);
// Ŀ¼ļǳļ֤ȡcount ЧԲеȡֽ
// ļǰдֵָļСöȡֽΪļ-ǰдֵָȡ
// 0򷵻0 ˳Ȼִļضȡֽ˳
  if (S_ISDIR (inode->i_mode) || S_ISREG (inode->i_mode))
    {
      if (count + file->f_pos > inode->i_size)
	count = inode->i_size - file->f_pos;
      if (count <= 0)
	return 0;
      return 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, int count)
{
  struct file *file;
  struct m_inode *inode;

// ļֵڳļNR_OPENҪдֽڼС0߸þ
// ļṹָΪգ򷵻س벢˳
  if (fd >= NR_OPEN || count < 0 || !(file = current->filp[fd]))
    return -EINVAL;
// ȡֽcount 0򷵻0˳
  if (!count)
    return 0;
// ȡļӦi ڵ㡣ǹܵļдܵļģʽдܵɹ򷵻
// дֽ򷵻س룬˳
  inode = file->f_inode;
  if (inode->i_pipe)
    return (file->f_mode & 2) ? write_pipe (inode, buf, count) : -EIO;
// ַļдַ豸дַ˳
  if (S_ISCHR (inode->i_mode))
    return rw_char (WRITE, inode->i_zone[0], buf, count, &file->f_pos);
// ǿ豸ļп豸ддֽ˳
  if (S_ISBLK (inode->i_mode))
    return block_write (inode->i_zone[0], &file->f_pos, buf, count);
// ǳļִļддֽ˳
  if (S_ISREG (inode->i_mode))
    return file_write (inode, file, buf, count);
// ʾӦڵļģʽس룬˳
  printk ("(Write)inode->i_mode=%06o\n\r", inode->i_mode);
  return -EINVAL;
}
