⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 write.c

📁 一个简单的操作系统minix的核心代码
💻 C
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
				src/fs/write.c	 	 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

24000	/* This file is the counterpart of "read.c".  It contains the code for writing
24001	 * insofar as this is not contained in read_write().
24002	 *
24003	 * The entry points into this file are
24004	 *   do_write:     call read_write to perform the WRITE system call
24005	 *   clear_zone:   erase a zone in the middle of a file
24006	 *   new_block:    acquire a new block
24007	 */
24008	
24009	#include "fs.h"
24010	#include <string.h>
24011	#include "buf.h"
24012	#include "file.h"
24013	#include "fproc.h"
24014	#include "inode.h"
24015	#include "super.h"
24016	
24017	FORWARD _PROTOTYPE( int write_map, (struct inode *rip, off_t position,
24018	                        zone_t new_zone)                                );
24019	
24020	FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) );
24021	
24022	/*===========================================================================*
24023	 *                              do_write                                     *
24024	 *===========================================================================*/
24025	PUBLIC int do_write()
24026	{
24027	/* Perform the write(fd, buffer, nbytes) system call. */
24028	
24029	  return(read_write(WRITING));
24030	}
	
	
24033	/*===========================================================================*
24034	 *                              write_map                                    *
24035	 *===========================================================================*/
24036	PRIVATE int write_map(rip, position, new_zone)
24037	register struct inode *rip;     /* pointer to inode to be changed */
24038	off_t position;                 /* file address to be mapped */
24039	zone_t new_zone;                /* zone # to be inserted */
24040	{
24041	/* Write a new zone into an inode. */
24042	  int scale, ind_ex, new_ind, new_dbl, zones, nr_indirects, single, zindex, ex;
24043	  zone_t z, z1;
24044	  register block_t b;
24045	  long excess, zone;
24046	  struct buf *bp;
24047	
24048	  rip->i_dirt = DIRTY;          /* inode will be changed */
24049	  bp = NIL_BUF;
24050	  scale = rip->i_sp->s_log_zone_size;           /* for zone-block conversion */
24051	  zone = (position/BLOCK_SIZE) >> scale;        /* relative zone # to insert */
24052	  zones = rip->i_ndzones;       /* # direct zones in the inode */
24053	  nr_indirects = rip->i_nindirs;/* # indirect zones per indirect block */
24054	
24055	  /* Is 'position' to be found in the inode itself? */
24056	  if (zone < zones) {
24057	        zindex = (int) zone;    /* we need an integer here */
24058	        rip->i_zone[zindex] = new_zone;
24059	        return(OK);
24060	  }
24061	
24062	  /* It is not in the inode, so it must be single or double indirect. */
24063	  excess = zone - zones;        /* first Vx_NR_DZONES don't count */
24064	  new_ind = FALSE;
24065	  new_dbl = FALSE;
24066	
24067	  if (excess < nr_indirects) {
24068	        /* 'position' can be located via the single indirect block. */
24069	        z1 = rip->i_zone[zones];        /* single indirect zone */
24070	        single = TRUE;
24071	  } else {
24072	        /* 'position' can be located via the double indirect block. */
24073	        if ( (z = rip->i_zone[zones+1]) == NO_ZONE) {
24074	                /* Create the double indirect block. */
24075	                if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
24076	                        return(err_code);
24077	                rip->i_zone[zones+1] = z;
24078	                new_dbl = TRUE; /* set flag for later */
24079	        }
24080	
24081	        /* Either way, 'z' is zone number for double indirect block. */
24082	        excess -= nr_indirects; /* single indirect doesn't count */
24083	        ind_ex = (int) (excess / nr_indirects);
24084	        excess = excess % nr_indirects;
24085	        if (ind_ex >= nr_indirects) return(EFBIG);
24086	        b = (block_t) z << scale;
24087	        bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ : NORMAL));
24088	        if (new_dbl) zero_block(bp);
24089	        z1 = rd_indir(bp, ind_ex);
24090	        single = FALSE;
24091	  }
24092	
24093	  /* z1 is now single indirect zone; 'excess' is index. */
24094	  if (z1 == NO_ZONE) {
24095	        /* Create indirect block and store zone # in inode or dbl indir blk. */
24096	        z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
24097	        if (single)
24098	                rip->i_zone[zones] = z1;        /* update inode */
24099	        else
24100	                wr_indir(bp, ind_ex, z1);       /* update dbl indir */
24101	
24102	        new_ind = TRUE;
24103	        if (bp != NIL_BUF) bp->b_dirt = DIRTY;  /* if double ind, it is dirty*/
24104	        if (z1 == NO_ZONE) {
24105	                put_block(bp, INDIRECT_BLOCK);  /* release dbl indirect blk */
24106	                return(err_code);       /* couldn't create single ind */
24107	        }
24108	  }
24109	  put_block(bp, INDIRECT_BLOCK);        /* release double indirect blk */
24110	
24111	  /* z1 is indirect block's zone number. */
24112	  b = (block_t) z1 << scale;
24113	  bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
24114	  if (new_ind) zero_block(bp);
24115	  ex = (int) excess;                    /* we need an int here */
24116	  wr_indir(bp, ex, new_zone);
24117	  bp->b_dirt = DIRTY;
24118	  put_block(bp, INDIRECT_BLOCK);
24119	
24120	  return(OK);
24121	}
	
	
24124	/*===========================================================================*
24125	 *                              wr_indir                                     *
24126	 *===========================================================================*/
24127	PRIVATE void wr_indir(bp, index, zone)
24128	struct buf *bp;                 /* pointer to indirect block */
24129	int index;                      /* index into *bp */
24130	zone_t zone;                    /* zone to write */
24131	{
24132	/* Given a pointer to an indirect block, write one entry. */
24133	
24134	  struct super_block *sp;
24135	
24136	  sp = get_super(bp->b_dev);    /* need super block to find file sys type */
24137	
24138	  /* write a zone into an indirect block */
24139	  if (sp->s_version == V1)
24140	        bp->b_v1_ind[index] = (zone1_t) conv2(sp->s_native, (int)  zone);
24141	  else
24142	        bp->b_v2_ind[index] = (zone_t)  conv4(sp->s_native, (long) zone);
24143	}
	
	
24146	/*===========================================================================*
24147	 *                              clear_zone                                   *
24148	 *===========================================================================*/
24149	PUBLIC void clear_zone(rip, pos, flag)
24150	register struct inode *rip;     /* inode to clear */
24151	off_t pos;                      /* points to block to clear */
24152	int flag;                       /* 0 if called by read_write, 1 by new_block */
24153	{
24154	/* Zero a zone, possibly starting in the middle.  The parameter 'pos' gives
24155	 * a byte in the first block to be zeroed.  Clearzone() is called from 
24156	 * read_write and new_block().
24157	 */
24158	
24159	  register struct buf *bp;
24160	  register block_t b, blo, bhi;
24161	  register off_t next;
24162	  register int scale;
24163	  register zone_t zone_size;
24164	
24165	  /* If the block size and zone size are the same, clear_zone() not needed. */
24166	  scale = rip->i_sp->s_log_zone_size;
24167	  if (scale == 0) return;
24168	
24169	  zone_size = (zone_t) BLOCK_SIZE << scale;
24170	  if (flag == 1) pos = (pos/zone_size) * zone_size;
24171	  next = pos + BLOCK_SIZE - 1;
24172	
24173	  /* If 'pos' is in the last block of a zone, do not clear the zone. */
24174	  if (next/zone_size != pos/zone_size) return;
24175	  if ( (blo = read_map(rip, next)) == NO_BLOCK) return;
24176	  bhi = (  ((blo>>scale)+1) << scale)   - 1;
24177	
24178	  /* Clear all the blocks between 'blo' and 'bhi'. */
24179	  for (b = blo; b <= bhi; b++) {
24180	        bp = get_block(rip->i_dev, b, NO_READ);
24181	        zero_block(bp);
24182	        put_block(bp, FULL_DATA_BLOCK);
24183	  }
24184	}
	
	
24187	/*===========================================================================*
24188	 *                              new_block                                    *
24189	 *===========================================================================*/
24190	PUBLIC struct buf *new_block(rip, position)
24191	register struct inode *rip;     /* pointer to inode */
24192	off_t position;                 /* file pointer */
24193	{
24194	/* Acquire a new block and return a pointer to it.  Doing so may require
24195	 * allocating a complete zone, and then returning the initial block.
24196	 * On the other hand, the current zone may still have some unused blocks.
24197	 */
24198	
24199	  register struct buf *bp;
24200	  block_t b, base_block;
24201	  zone_t z;
24202	  zone_t zone_size;
24203	  int scale, r;
24204	  struct super_block *sp;
24205	
24206	  /* Is another block available in the current zone? */
24207	  if ( (b = read_map(rip, position)) == NO_BLOCK) {
24208	        /* Choose first zone if possible. */
24209	        /* Lose if the file is nonempty but the first zone number is NO_ZONE
24210	         * corresponding to a zone full of zeros.  It would be better to
24211	         * search near the last real zone.
24212	         */
24213	        if (rip->i_zone[0] == NO_ZONE) {
24214	                sp = rip->i_sp;
24215	                z = sp->s_firstdatazone;
24216	        } else {
24217	                z = rip->i_zone[0];     /* hunt near first zone */
24218	        }
24219	        if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
24220	        if ( (r = write_map(rip, position, z)) != OK) {
24221	                free_zone(rip->i_dev, z);
24222	                err_code = r;
24223	                return(NIL_BUF);
24224	        }
24225	
24226	        /* If we are not writing at EOF, clear the zone, just to be safe. */
24227	        if ( position != rip->i_size) clear_zone(rip, position, 1);
24228	        scale = rip->i_sp->s_log_zone_size;
24229	        base_block = (block_t) z << scale;
24230	        zone_size = (zone_t) BLOCK_SIZE << scale;
24231	        b = base_block + (block_t)((position % zone_size)/BLOCK_SIZE);
24232	  }
24233	
24234	  bp = get_block(rip->i_dev, b, NO_READ);
24235	  zero_block(bp);
24236	  return(bp);
24237	}
	
	
24240	/*===========================================================================*
24241	 *                              zero_block                                   *
24242	 *===========================================================================*/
24243	PUBLIC void zero_block(bp)
24244	register struct buf *bp;        /* pointer to buffer to zero */
24245	{
24246	/* Zero a block. */
24247	
24248	  memset(bp->b_data, 0, BLOCK_SIZE);
24249	  bp->b_dirt = DIRTY;
24250	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -