431 lines
12 KiB
C
431 lines
12 KiB
C
/*
|
|
* Copyright (c) 1986 Regents of the University of California.
|
|
* All rights reserved. The Berkeley software License Agreement
|
|
* specifies the terms and conditions for redistribution.
|
|
*/
|
|
|
|
/*
|
|
* The I node is the focus of all file activity in UNIX.
|
|
* There is a unique inode allocated for each active file,
|
|
* each current directory, each mounted-on file, text file, and the root.
|
|
* An inode is 'named' by its dev/inumber pair. (iget/iget.c)
|
|
* Data in icommon1 and icommon2 is read in from permanent inode on volume.
|
|
*/
|
|
|
|
/*
|
|
* 28 of the di_addr address bytes are used; 7 addresses of 4
|
|
* bytes each: 4 direct (4Kb directly accessible) and 3 indirect.
|
|
*/
|
|
#define NDADDR 4 /* direct addresses in inode */
|
|
#define NIADDR 3 /* indirect addresses in inode */
|
|
#define NADDR (NDADDR + NIADDR) /* total addresses in inode */
|
|
|
|
struct icommon1 {
|
|
u_short ic_mode; /* mode and type of file */
|
|
u_short ic_nlink; /* number of links to file */
|
|
uid_t ic_uid; /* owner's user id */
|
|
gid_t ic_gid; /* owner's group id */
|
|
off_t ic_size; /* number of bytes in file */
|
|
};
|
|
|
|
struct icommon2 {
|
|
time_t ic_atime; /* time last accessed */
|
|
time_t ic_mtime; /* time last modified */
|
|
time_t ic_ctime; /* time created */
|
|
};
|
|
|
|
struct inode {
|
|
struct inode *i_chain[2]; /* must be first */
|
|
u_int i_flag;
|
|
u_int i_count; /* reference count */
|
|
dev_t i_dev; /* device where inode resides */
|
|
ino_t i_number; /* i number, 1-to-1 with device address */
|
|
u_int i_id; /* unique identifier */
|
|
struct fs *i_fs; /* file sys associated with this inode */
|
|
union {
|
|
struct {
|
|
u_short I_shlockc; /* count of shared locks */
|
|
u_short I_exlockc; /* count of exclusive locks */
|
|
} i_l;
|
|
struct proc *I_rsel; /* pipe read select */
|
|
} i_un0;
|
|
union {
|
|
struct proc *I_wsel; /* pipe write select */
|
|
} i_un1;
|
|
union {
|
|
daddr_t I_addr[NADDR]; /* normal file/directory */
|
|
struct {
|
|
daddr_t I_db[NDADDR]; /* normal file/directory */
|
|
daddr_t I_ib[NIADDR];
|
|
} i_f;
|
|
struct {
|
|
/*
|
|
* the dummy field is here so that the de/compression
|
|
* part of the iget/iput routines works for special
|
|
* files.
|
|
*/
|
|
u_int I_dummy;
|
|
dev_t I_rdev; /* dev type */
|
|
} i_d;
|
|
} i_un2;
|
|
union {
|
|
daddr_t if_lastr; /* last read (read-ahead) */
|
|
struct {
|
|
struct inode *if_freef; /* free list forward */
|
|
struct inode **if_freeb; /* free list back */
|
|
} i_fr;
|
|
} i_un3;
|
|
struct icommon1 i_ic1;
|
|
u_int i_flags; /* user changeable flags */
|
|
struct icommon2 i_ic2;
|
|
};
|
|
|
|
/*
|
|
* Inode structure as it appears on
|
|
* a disk block.
|
|
*/
|
|
struct dinode {
|
|
struct icommon1 di_icom1;
|
|
daddr_t di_addr[NADDR]; /* 7 block addresses 4 bytes each */
|
|
u_int di_reserved[1]; /* pad of 4 to make total size 64 */
|
|
u_int di_flags;
|
|
struct icommon2 di_icom2;
|
|
};
|
|
|
|
#define i_mode i_ic1.ic_mode
|
|
#define i_nlink i_ic1.ic_nlink
|
|
#define i_uid i_ic1.ic_uid
|
|
#define i_gid i_ic1.ic_gid
|
|
#define i_size i_ic1.ic_size
|
|
#define i_shlockc i_un0.i_l.I_shlockc
|
|
#define i_exlockc i_un0.i_l.I_exlockc
|
|
#define i_rsel i_un0.I_rsel
|
|
#define i_wsel i_un1.I_wsel
|
|
#define i_db i_un2.i_f.I_db
|
|
#define i_ib i_un2.i_f.I_ib
|
|
#define i_atime i_ic2.ic_atime
|
|
#define i_mtime i_ic2.ic_mtime
|
|
#define i_ctime i_ic2.ic_ctime
|
|
#define i_rdev i_un2.i_d.I_rdev
|
|
#define i_addr i_un2.I_addr
|
|
#define i_dummy i_un2.i_d.I_dummy
|
|
#define i_lastr i_un3.if_lastr
|
|
#define i_forw i_chain[0]
|
|
#define i_back i_chain[1]
|
|
#define i_freef i_un3.i_fr.if_freef
|
|
#define i_freeb i_un3.i_fr.if_freeb
|
|
|
|
#define di_ic1 di_icom1
|
|
#define di_ic2 di_icom2
|
|
#define di_mode di_ic1.ic_mode
|
|
#define di_nlink di_ic1.ic_nlink
|
|
#define di_uid di_ic1.ic_uid
|
|
#define di_gid di_ic1.ic_gid
|
|
#define di_size di_ic1.ic_size
|
|
#define di_atime di_ic2.ic_atime
|
|
#define di_mtime di_ic2.ic_mtime
|
|
#define di_ctime di_ic2.ic_ctime
|
|
|
|
#ifdef KERNEL
|
|
struct stat;
|
|
|
|
/*
|
|
* Invalidate an inode. Used by the namei cache to detect stale
|
|
* information. In order to save space and also reduce somewhat the
|
|
* overhead - the i_id field is made into a u_short. If a pdp-11 can
|
|
* invalidate 100 inodes per second, the cache will have to be invalidated
|
|
* in about 11 minutes. Ha!
|
|
* Assumes the cacheinvalall routine will map the namei cache.
|
|
*/
|
|
void cinvalall (void);
|
|
|
|
#define cacheinval(ip) \
|
|
(ip)->i_id = ++nextinodeid; \
|
|
if (nextinodeid == 0) \
|
|
cinvalall();
|
|
|
|
u_int nextinodeid; /* unique id generator */
|
|
|
|
extern struct inode inode[]; /* the inode table itself */
|
|
struct inode *rootdir; /* pointer to inode of root directory */
|
|
|
|
/*
|
|
* Initialize hash links for inodes and build inode free list.
|
|
*/
|
|
void ihinit (void);
|
|
|
|
/*
|
|
* Get an inode pointer of a file descriptor.
|
|
*/
|
|
struct inode *getinode (int fdes);
|
|
|
|
/*
|
|
* Allocate an inode in the file system.
|
|
*/
|
|
struct inode *ialloc (struct inode *pip);
|
|
|
|
/*
|
|
* Look up an inode by device, inumber.
|
|
*/
|
|
struct inode *iget (dev_t dev, struct fs *fs, ino_t ino);
|
|
|
|
/*
|
|
* Dereference an inode structure. On the last reference,
|
|
* write the inode out and deallocate the file.
|
|
*/
|
|
void iput (struct inode *ip);
|
|
|
|
/*
|
|
* Make a new file.
|
|
*/
|
|
struct nameidata;
|
|
struct inode *maknode (int mode, struct nameidata *ndp);
|
|
|
|
/*
|
|
* Open inode: initialize and validate special files.
|
|
*/
|
|
int openi (struct inode *ip, int mode);
|
|
|
|
/*
|
|
* Close inode: call the device driver for special (IBLK, ICHR) files.
|
|
*/
|
|
int closei (struct inode *ip, int flag);
|
|
|
|
/*
|
|
* Convert a pathname into a pointer to a locked inode.
|
|
*/
|
|
struct inode *namei (struct nameidata *ndp);
|
|
|
|
enum uio_rw;
|
|
int rdwri (enum uio_rw rw, struct inode *ip, caddr_t base, int len,
|
|
off_t offset, int ioflg, int *aresid);
|
|
|
|
struct uio;
|
|
int rwip (struct inode *ip, struct uio *uio, int ioflag);
|
|
|
|
/*
|
|
* Check mode permission on inode pointer.
|
|
*/
|
|
int access (struct inode *ip, int mode);
|
|
|
|
/*
|
|
* Change the mode on a file.
|
|
*/
|
|
int chmod1 (struct inode *ip, int mode);
|
|
|
|
/*
|
|
* Change an owner of a file.
|
|
*/
|
|
int chown1 (struct inode *ip, int uid, int gid);
|
|
|
|
/*
|
|
* Lock/unlock an inode.
|
|
*/
|
|
void ilock (struct inode *ip);
|
|
void iunlock (struct inode *ip);
|
|
|
|
/*
|
|
* Get inode statistics.
|
|
*/
|
|
int ino_stat (struct inode *ip, struct stat *sb);
|
|
|
|
/*
|
|
* Truncate the inode ip to at most length size.
|
|
*/
|
|
void itrunc (struct inode *oip, u_long length, int ioflags);
|
|
|
|
/*
|
|
* Update the inode with the current time.
|
|
*/
|
|
struct timeval;
|
|
void iupdat (struct inode *ip, struct timeval *ta, struct timeval *tm,
|
|
int waitfor);
|
|
|
|
void irele (struct inode *ip);
|
|
|
|
/*
|
|
* Free an inode.
|
|
*/
|
|
void ifree (struct inode *ip, ino_t ino);
|
|
|
|
/*
|
|
* Free a block or fragment.
|
|
*/
|
|
void free (struct inode *ip, daddr_t bno);
|
|
|
|
/*
|
|
* Flush all the blocks associated with an inode.
|
|
*/
|
|
void syncip (struct inode *ip);
|
|
|
|
/*
|
|
* Remove any inodes in the inode cache belonging to dev.
|
|
*/
|
|
int iflush (dev_t dev);
|
|
|
|
/*
|
|
* Convert a pointer to an inode into a reference to an inode.
|
|
*/
|
|
void igrab (struct inode *ip);
|
|
|
|
/*
|
|
* Check if source directory is in the path of the target directory.
|
|
*/
|
|
int checkpath (struct inode *source, struct inode *target);
|
|
|
|
/*
|
|
* Check if a directory is empty or not.
|
|
*/
|
|
int dirempty (struct inode *ip, ino_t parentino);
|
|
|
|
/*
|
|
* Rewrite an existing directory entry to point at the inode supplied.
|
|
*/
|
|
void dirrewrite (struct inode *dp, struct inode *ip, struct nameidata *ndp);
|
|
|
|
/*
|
|
* Check that device is mounted somewhere.
|
|
*/
|
|
int ufs_mountedon (dev_t dev);
|
|
|
|
/*
|
|
* Set the attributes on a file. This was placed here because ufs_syscalls
|
|
* is too large already (it will probably be split into two files eventually).
|
|
*/
|
|
struct vattr;
|
|
int ufs_setattr (struct inode *ip, struct vattr *vap);
|
|
|
|
/*
|
|
* Cache flush, called when filesys is umounted.
|
|
*/
|
|
void nchinval (dev_t dev);
|
|
|
|
#endif /* KERNEL */
|
|
|
|
/* i_flag */
|
|
#define ILOCKED 0x1 /* inode is locked */
|
|
#define IUPD 0x2 /* file has been modified */
|
|
#define IACC 0x4 /* inode access time to be updated */
|
|
#define IMOUNT 0x8 /* inode is mounted on */
|
|
#define IWANT 0x10 /* some process waiting on lock */
|
|
#define ITEXT 0x20 /* inode is pure text prototype */
|
|
#define ICHG 0x40 /* inode has been changed */
|
|
#define ISHLOCK 0x80 /* file has shared lock */
|
|
#define IEXLOCK 0x100 /* file has exclusive lock */
|
|
#define ILWAIT 0x200 /* someone waiting on file lock */
|
|
#define IMOD 0x400 /* inode has been modified */
|
|
#define IRENAME 0x800 /* inode is being renamed */
|
|
#define IPIPE 0x1000 /* inode is a pipe */
|
|
#define IRCOLL 0x2000 /* read select collision on pipe */
|
|
#define IWCOLL 0x4000 /* write select collision on pipe */
|
|
#define IXMOD 0x8000 /* inode is text, but impure (XXX) */
|
|
|
|
/* i_mode */
|
|
#define IFMT 0170000 /* type of file */
|
|
#define IFCHR 0020000 /* character special */
|
|
#define IFDIR 0040000 /* directory */
|
|
#define IFBLK 0060000 /* block special */
|
|
#define IFREG 0100000 /* regular */
|
|
#define IFLNK 0120000 /* symbolic link */
|
|
#define IFSOCK 0140000 /* socket */
|
|
#define ISUID 04000 /* set user id on execution */
|
|
#define ISGID 02000 /* set group id on execution */
|
|
#define ISVTX 01000 /* save swapped text even after use */
|
|
#define IREAD 0400 /* read, write, execute permissions */
|
|
#define IWRITE 0200
|
|
#define IEXEC 0100
|
|
|
|
#ifdef KERNEL
|
|
/*
|
|
* Flags for va_cflags.
|
|
*/
|
|
#define VA_UTIMES_NULL 0x01 /* utimes argument was NULL */
|
|
|
|
/*
|
|
* Flags for ioflag.
|
|
*/
|
|
#define IO_UNIT 0x01 /* do I/O as atomic unit */
|
|
#define IO_APPEND 0x02 /* append write to end */
|
|
#define IO_SYNC 0x04 /* do I/O synchronously */
|
|
/*#define IO_NODELOCKED 0x08 not implemented */
|
|
#define IO_NDELAY 0x10 /* FNDELAY flag set in file table */
|
|
|
|
|
|
/*
|
|
* This is a bit of a misnomer. 2.11BSD does not have 'vnodes' but it was
|
|
* easier/simpler to keep the name 'vattr' than changing the name to something
|
|
* like 'iattr'.
|
|
*
|
|
* This structure is a _subset_ of 4.4BSD's vnode attribute structure. ONLY
|
|
* those attributes which can be *changed by the user* are present. Since we
|
|
* do not have vnodes why initialize (and carry around) un-used members.
|
|
*/
|
|
struct vattr {
|
|
mode_t va_mode;
|
|
uid_t va_uid;
|
|
gid_t va_gid;
|
|
off_t va_size;
|
|
time_t va_atime;
|
|
time_t va_mtime;
|
|
u_int va_flags;
|
|
u_int va_vaflags;
|
|
};
|
|
|
|
/*
|
|
* Token indicating no attribute value yet assigned.
|
|
*/
|
|
#define VNOVAL (-1)
|
|
|
|
/*
|
|
* Initialize a inode attribute structure.
|
|
*/
|
|
#define VATTR_NULL(vp) { \
|
|
(vp)->va_mode = VNOVAL; \
|
|
(vp)->va_uid = VNOVAL; \
|
|
(vp)->va_gid = VNOVAL; \
|
|
(vp)->va_size = VNOVAL; \
|
|
(vp)->va_atime = VNOVAL; \
|
|
(vp)->va_mtime = VNOVAL; \
|
|
(vp)->va_flags = VNOVAL; \
|
|
(vp)->va_vaflags = VNOVAL; }
|
|
|
|
/*
|
|
* N.B: If the above structure changes be sure to modify the function
|
|
* vattr_null in pdp/mch_xxx.s!
|
|
*/
|
|
#endif
|
|
|
|
#define ILOCK(ip) { \
|
|
while ((ip)->i_flag & ILOCKED) { \
|
|
(ip)->i_flag |= IWANT; \
|
|
sleep((caddr_t)(ip), PINOD); \
|
|
} \
|
|
(ip)->i_flag |= ILOCKED; \
|
|
}
|
|
|
|
#define IUNLOCK(ip) { \
|
|
(ip)->i_flag &= ~ILOCKED; \
|
|
if ((ip)->i_flag&IWANT) { \
|
|
(ip)->i_flag &= ~IWANT; \
|
|
wakeup((caddr_t)(ip)); \
|
|
} \
|
|
}
|
|
|
|
#define IUPDAT(ip, t1, t2, waitfor) { \
|
|
if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) \
|
|
iupdat(ip, t1, t2, waitfor); \
|
|
}
|
|
|
|
#define ITIMES(ip, t1, t2) { \
|
|
if ((ip)->i_flag&(IUPD|IACC|ICHG)) { \
|
|
(ip)->i_flag |= IMOD; \
|
|
if ((ip)->i_flag&IACC) \
|
|
(ip)->i_atime = (t1)->tv_sec; \
|
|
if ((ip)->i_flag&IUPD) \
|
|
(ip)->i_mtime = (t2)->tv_sec; \
|
|
if ((ip)->i_flag&ICHG) \
|
|
(ip)->i_ctime = time.tv_sec; \
|
|
(ip)->i_flag &= ~(IACC|IUPD|ICHG); \
|
|
} \
|
|
}
|