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

#include <string.h>		// ַͷļҪһЩйַǶ뺯
#include <errno.h>		// ͷļϵͳиֳš(Linus minix )
#include <fcntl.h>		// ļͷļļĲƳŵĶ塣
#include <sys/types.h>		// ͷļ˻ϵͳ͡
#include <utime.h>		// ûʱͷļ˷ʺ޸ʱṹԼutime()ԭ͡
#include <sys/stat.h>		// ļ״̬ͷļļļϵͳ״̬ṹstat{}ͳ

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

// ȡļϵͳϢϵͳú
int
sys_ustat (int dev, struct ustat *ubuf)
{
  return -ENOSYS;
}

//// ļʺ޸ʱ䡣
// filename ļtimes Ƿʺ޸ʱṹָ롣
// times ָ벻ΪNULLȡutimbuf ṹеʱϢļķʺ޸ʱ䡣
// times ָNULLȡϵͳǰʱָļķʺ޸ʱ
int
sys_utime (char *filename, struct utimbuf *times)
{
  struct m_inode *inode;
  long actime, modtime;

// ļѰҶӦi ڵ㣬ûҵ򷵻س롣
  if (!(inode = namei (filename)))
    return -ENOENT;
// ʺ޸ʱݽṹָ벻ΪNULLӽṹжȡûõʱֵ
  if (times)
    {
      actime = get_fs_long ((unsigned long *) &times->actime);
      modtime = get_fs_long ((unsigned long *) &times->modtime);
// 򽫷ʺ޸ʱΪǰʱ䡣
    }
  else
    actime = modtime = CURRENT_TIME;
// ޸i ڵеķʱֶκ޸ʱֶΡ
  inode->i_atime = actime;
  inode->i_mtime = modtime;
// i ڵ޸ı־ͷŸýڵ㣬0
  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.
*/
/*
* ļXXXǸʵûid ЧûidBSD ϵͳʹʵûid
* ʹõÿԹsetuid ʹáעPOSIX ׼ʹʵûID
*/
//// ļķȨޡ
// filename ļmode 룬R_OK(4)W_OK(2)X_OK(1)F_OK(0)ɡ
// Ļ򷵻0򷵻س롣
int
sys_access (const char *filename, int mode)
{
  struct m_inode *inode;
  int res, i_mode;

// ɵ3 λɣи߱λ
  mode &= 0007;
// ļӦi ڵ㲻ڣ򷵻س롣
  if (!(inode = namei (filename)))
    return -EACCES;
// ȡļ룬ͷŸi ڵ㡣
  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;
// ļԾвѯλɣ0
  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.
*/
/*
* XXX ĲԣΪʵҪЧûid 
* ʵûidʱأȻŵsuser()ȷʵҪ
* suser()Ҫűá
*/
// ǰûid Ϊ0ûִλ0 ļԱκ˷ʣ򷵻0
  if ((!current->uid) && (!(mode & 1) || (i_mode & 0111)))
    return 0;
// 򷵻س롣
  return -EACCES;
}

//// ı䵱ǰĿ¼ϵͳú
// filename Ŀ¼
// ɹ򷵻0򷵻س롣
int
sys_chdir (const char *filename)
{
  struct m_inode *inode;

// ļӦi ڵ㲻ڣ򷵻س롣
  if (!(inode = namei (filename)))
    return -ENOENT;
// i ڵ㲻Ŀ¼i ڵ㣬ͷŸýڵ㣬س롣
  if (!S_ISDIR (inode->i_mode))
    {
      iput (inode);
      return -ENOTDIR;
    }
// ͷŵǰԭĿ¼i ڵ㣬ָõĹĿ¼i ڵ㡣0
  iput (current->pwd);
  current->pwd = inode;
  return (0);
}

//// ıĿ¼ϵͳú
// ָ·ΪĿ¼'/'
// ɹ򷵻0򷵻س롣
int
sys_chroot (const char *filename)
{
  struct m_inode *inode;

// ļӦi ڵ㲻ڣ򷵻س롣
  if (!(inode = namei (filename)))
    return -ENOENT;
// i ڵ㲻Ŀ¼i ڵ㣬ͷŸýڵ㣬س롣
  if (!S_ISDIR (inode->i_mode))
    {
      iput (inode);
      return -ENOTDIR;
    }
// ͷŵǰ̵ĸĿ¼i ڵ㣬ΪָĿ¼i ڵ㣬0
  iput (current->root);
  current->root = inode;
  return (0);
}

//// ޸ļϵͳú
// filename ļmode µļԡ
// ɹ򷵻0򷵻س롣
int
sys_chmod (const char *filename, int mode)
{
  struct m_inode *inode;

// ļӦi ڵ㲻ڣ򷵻س롣
  if (!(inode = namei (filename)))
    return -ENOENT;
// ǰ̵Чûid ļi ڵûidҵǰ̲ǳûͷŸ
// ļi ڵ㣬س롣
  if ((current->euid != inode->i_uid) && !suser ())
    {
      iput (inode);
      return -EACCES;
    }
// i ڵļԣøi ڵ޸ı־ͷŸi ڵ㣬0
  inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
  inode->i_dirt = 1;
  iput (inode);
  return 0;
}

//// ޸ļϵͳú
// filename ļuid ûʶ(ûid)gid id
// ɹ򷵻0򷵻س롣
int
sys_chown (const char *filename, int uid, int gid)
{
  struct m_inode *inode;

// ļӦi ڵ㲻ڣ򷵻س롣
  if (!(inode = namei (filename)))
    return -ENOENT;
// ǰ̲ǳûͷŸi ڵ㣬س롣
  if (!suser ())
    {
      iput (inode);
      return -EACCES;
    }
// ļӦi ڵûid idi ڵѾ޸ı־ͷŸi ڵ㣬0
  inode->i_uid = uid;
  inode->i_gid = gid;
  inode->i_dirt = 1;
  iput (inode);
  return 0;
}

//// 򿪣򴴽ļϵͳú
// filename ļflag Ǵļ־ֻO_RDONLYֻдO_WRONLY дO_RDWR
// ԼO_CREATO_EXCLO_APPEND һЩ־ϣһļmode
// ָʹļԣЩS_IRWXU(ļждִȨ)S_IRUSR
// (ûжļȨ)S_IRWXG(ԱждִȨ)ȵȡ´ļЩ
// ֻӦڽļķʣֻļĴ򿪵Ҳһɶдļ
// ɹ򷵻ļ(ļ)򷵻س롣(μsys/stat.h, fcntl.h)
int
sys_open (const char *filename, int flag, int mode)
{
  struct m_inode *inode;
  struct file *f;
  int i, fd;

// ûõģʽ̵ģʽ룬ɵļģʽ
  mode &= 0777 & ~current->umask;
// ̽ṹļṹָ飬һѾûп򷵻س롣
  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 )Ѿûп
// ļṹ򷵻س롣
  f = 0 + file_table;
  for (i = 0; i < NR_FILE; i++, f++)
    if (!f->f_count)
      break;
  if (i >= NR_FILE)
    return -EINVAL;
// ý̵ĶӦļļṹָָļṹü1
  (current->filp[fd] = f)->f_count++;
// úִд򿪲ֵС0˵ͷŸ뵽ļṹس롣
  if ((i = open_namei (filename, flag, mode, &inode)) < 0)
    {
      current->filp[fd] = NULL;
      f->f_count = 0;
      return i;
    }
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
/* ttys Щ⣨ttyxx ==4tty ==5*/
// ַ豸ļô豸4 Ļõǰ̵tty Ϊi ڵ豸š
// õǰtty Ӧtty ĸŵڽ̵ĸš
  if (S_ISCHR (inode->i_mode))
    if (MAJOR (inode->i_zone[0]) == 4)
      {
	if (current->leader && current->tty < 0)
	  {
	    current->tty = MINOR (inode->i_zone[0]);
	    tty_table[current->tty].pgrp = current->pgrp;
	  }
// ַļ豸5 Ļǰûtty˵ͷi ڵ뵽
// ļṹس롣
      }
    else if (MAJOR (inode->i_zone[0]) == 5)
      if (current->tty < 0)
	{
	  iput (inode);
	  current->filp[fd] = NULL;
	  f->f_count = 0;
	  return -EPERM;
	}
/* Likewise with block-devices: check for floppy_change */
/* ͬڿ豸ļҪƬǷ񱻸 */
// 򿪵ǿ豸ļƬǷҪǸٻжӦ豸
// ʧЧ
  if (S_ISBLK (inode->i_mode))
    check_disk_change (inode->i_zone[0]);
// ʼļṹļṹԺͱ־þüΪ1i ڵֶΣļдָ
// ʼΪ0ļ
  f->f_mode = inode->i_mode;
  f->f_flags = flag;
  f->f_count = 1;
  f->f_inode = inode;
  f->f_pos = 0;
  return (fd);
}

//// ļϵͳú
// pathname ·mode sys_open()ͬ
// ɹ򷵻ļ򷵻س롣
int
sys_creat (const char *pathname, int mode)
{
  return sys_open (pathname, O_CREAT | O_TRUNC, mode);
}

// رļϵͳú
// fd ļ
// ɹ򷵻0򷵻س롣
int
sys_close (unsigned int fd)
{
  struct file *filp;

// ļֵڳͬʱܴ򿪵ļ򷵻س롣
  if (fd >= NR_OPEN)
    return -EINVAL;
// λ̵ִʱرļλͼӦλ
  current->close_on_exec &= ~(1 << fd);
// ļӦļṹָNULL򷵻س롣
  if (!(filp = current->filp[fd]))
    return -EINVAL;
// øļļṹָΪNULL
  current->filp[fd] = NULL;
// ڹرļ֮ǰӦļṹеľüѾΪ0˵ں˳
  if (filp->f_count == 0)
    panic ("Close: file count is 0");
// 򽫶Ӧļṹľü1Ϊ0򷵻0ɹѵ0˵
// ļѾûоãͷŸļi ڵ㣬0
  if (--filp->f_count)
    return (0);
  iput (filp->f_inode);
  return (0);
}
