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

📄 es_file.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	    written = -2;#ifdef DEBUG	    (void) fprintf(stderr,			   "Failed write in %s of %d chars\n",			   "es_file_flush_write_buf", buf->used);#endif	    goto Return;	}	if (buf->start+written > private->length_on_disk) {	    /* Extending file on disk, so make sure bytes make it. */	    if (fsync(private->fd) == -1) {		private->status = ES_FSYNC_FAILED;#ifdef DEBUG		(void) fprintf(stderr,				"Failed fsynch in es_file_flush_write_buf\n");#endif		/* BUG ALERT!  Who knows what state the file is in? */		written = -3;		goto Return;	    }	    private->length_on_disk = buf->start+written;	}	BUF_INVALIDATE(buf);Return:	return(written);} static intes_file_move_write_buf(private, include, also_include, include_offset)	register Es_file_data	  private;	register Es_index	  include, also_include;	char			**include_offset;/* * Caller ensures: *	include <= also_include < include+WRITE_BUF_LEN < ES_INFINITY, *	include <= private->length * Return values: *	< 0 indicate various errors, *	= 0 implies write_buf already correctly positioned, *	> 0 implies write_buf written then moved. * Assumptions: *	if you have to write any bytes, you might as well write them all. *	if you have to read any bytes, you might as well read them all. */{	register Es_file_buf	buf = &private->write_buf;	register Es_file_buf	read_buf;	register int		written = 0;	Es_index		buf_last_plus_one;	if (buf->used == 0)	    goto Fill_Buffer;	buf_last_plus_one = BUF_LAST_PLUS_ONE(buf);#ifdef DEBUG	if (buf_last_plus_one > private->length)	    take_breakpoint();#endif	/* Buffer must contain include and also_include.	 * There are two possible problems, even if include is contained:	 * 1) include is too far into the buffer for also_include to also be	 *    contained, or	 * 2) there is space available in the buffer for also_include, but	 *    the buffer needs to fill in bytes from the disk between	 *    its current end and also_include.	 * If include is at buffer end, or also_include is at or beyond	 * buffer end, it may be possible to simply extend the buffer iff	 * buffer is at the end of the stream and it has room left.	 */	if (include < buf->start || include > buf_last_plus_one ||	    (include == buf_last_plus_one &&	     include >= buf->start+WRITE_BUF_LEN)		||	    (also_include >= buf_last_plus_one &&	     (buf_last_plus_one < private->length ||	      also_include >= buf->start+WRITE_BUF_LEN))	   ) {	    written = es_file_flush_write_buf(private, &private->write_buf);	    if (written < 0)		goto Return;	    /* Possible future optimizations:	     *	1) Deal with buf_last_plus_one <= also_include	     *		< buf->start+WRITE_BUF_LEN	     *	2) Slide buffer around to avoid full read when possible	     *	3) Copy from read_buf to avoid full read when possible	     */Fill_Buffer:	    if (es_file_fill_buf(private, buf, include,	    	include+WRITE_BUF_LEN > private->length_on_disk	    	? private->length_on_disk : include+WRITE_BUF_LEN) < 0) {	    	written = -4;	    	goto Return;	    }	}	*include_offset = buf->chars + (include - buf->start);Return:	return(written);} static voides_file_maybe_truncate_buf(buf, new_last_plus_one)	register Es_file_buf	buf;	register Es_index	new_last_plus_one;{	if (buf->used > 0 && new_last_plus_one < BUF_LAST_PLUS_ONE(buf)) {	    buf->used = (new_last_plus_one < buf->start)			? 0 : new_last_plus_one - buf->start;	}} static Es_statuses_file_commit(esh)        Es_handle esh;{	register Es_file_data	private = ABS_TO_REP(esh);	if (es_file_flush_write_buf(private, &private->write_buf) < 0) {	    return(private->status);	}	private->flags |= COMMIT_DONE;	return(ES_SUCCESS);} static Es_handlees_file_destroy(esh)        Es_handle esh;{        register Es_file_data private = ABS_TO_REP(esh);	if (private->write_buf.chars) {#ifdef DEBUG	    if ((private->write_buf.used > 0) &&		(private->flags & COMMIT_DONE)) {		/* Caller should have called es_commit in order to guarantee		 * appropriate recovery in case of errors.		 */		take_breakpoint();	    }#endif	    free(private->write_buf.chars);	}	(void) close(private->fd); private->fd = -1;	if ((private->options & ES_OPT_APPEND) &&	    (private->flags & COMMIT_DONE) == 0) {	    (void) unlink(private->name);	}	free((char *)esh);	free(private->read_buf.chars);#ifndef BACKUP_AT_HEAD_OF_LINK	free(private->true_name);#endif	free(private->name);	free((char *)private);	return(NULL);}static Es_indexes_file_get_length(esh)        Es_handle esh;  {	register Es_file_data private = ABS_TO_REP(esh);        return(private->length);} static Es_indexes_file_get_position(esh)        Es_handle esh;  {        register Es_file_data private = ABS_TO_REP(esh);        return(private->pos);} static Es_indexes_file_set_position(esh, pos)        Es_handle		esh;        register Es_index	pos;{        register Es_file_data private = ABS_TO_REP(esh);	if (pos > private->length)		pos = private->length;	private->pos = pos;	return(private->pos);}  static Es_indexes_file_read(esh, count, buf, count_read)        Es_handle		 esh;	int			 count;	register int		*count_read;	caddr_t			 buf;/* * Needed characters may be in the read_buf, the write_buf, or on disk, or * some combination of all three. */{	register Es_file_data	 private = ABS_TO_REP(esh);	register Es_index	 pos = private->pos, lpo;	register int		 to_read, still_needed;	es_file_buf		 dummy_read_buf;	char			*offset;	/* Client may request more bytes than are available, so count cannot	 * be trusted in the following code.	 */	*count_read = (count > private->length - pos) 		      ? (private->length - pos) : count;	for (still_needed = *count_read;	     still_needed > 0;	     still_needed -= to_read, pos += to_read) {	    /* Figure out where the next set of characters is coming from.	     * The write_buf has precedence over the read_buf in the tests	     * so that overlap range reads from the write_buf!	     */	    if (BUF_CONTAINS_POS(&private->write_buf, pos)) {		to_read = BUF_LAST_PLUS_ONE(&private->write_buf) - pos;		if (to_read > still_needed)		    to_read = still_needed;		bcopy(private->write_buf.chars+(pos-private->write_buf.start),		      buf + (*count_read-still_needed), to_read);	    } else if (BUF_CONTAINS_POS(&private->read_buf, pos)) {		to_read = BUF_LAST_PLUS_ONE(&private->read_buf) - pos;		if (to_read > still_needed)		    to_read = still_needed;		bcopy(private->read_buf.chars+(pos-private->read_buf.start),		      buf + (*count_read-still_needed), to_read);	    } else if (still_needed <= READ_BUF_LEN) {		/* Since we have to read from disk, might as well get as		 * many characters as possible.		 */		lpo = pos + READ_BUF_LEN;		if (lpo > private->length_on_disk)		    lpo = private->length_on_disk;		/* Overlap with write_buf is avoided for good hygiene. */		if (private->write_buf.used > 0 &&		    pos < private->write_buf.start &&		    lpo > private->write_buf.start)		    lpo = private->write_buf.start;		if (es_file_fill_buf(private, &private->read_buf, pos, lpo)		    < 0) {		    *count_read = 0;		    pos = private->pos;		    goto Return;		}		/* Go around again and characters will get copied		 * from read_buf in earlier part of loop.		 */		to_read = 0;	    } else {		/* Read directly from the disk */		dummy_read_buf.chars = buf + (*count_read-still_needed);		lpo = pos + still_needed;		if (lpo > private->length_on_disk)		    lpo = private->length_on_disk;		/* Overlap with write_buf is forbidden. */		if (private->write_buf.used > 0 &&		    lpo > private->write_buf.start)		    lpo = private->write_buf.start;		if (es_file_fill_buf(private, &dummy_read_buf, pos, lpo)		    < 0) {		    *count_read = 0;		    pos = private->pos;		    goto Return;		}		to_read = dummy_read_buf.used;	    }	}Return:	private->pos = pos;	return(pos);}/* Following enumeration details the three possible types of replace. */typedef enum {esfr_truncate, esfr_overwrite, esfr_insert} Esfr_mode; static Es_indexes_file_replace(esh, last_plus_one, count, buf, count_used)         Es_handle		 esh;        register int		 count;        int			*count_used, last_plus_one;        caddr_t			 buf;  { 	register Es_file_data	 private = ABS_TO_REP(esh);	register Esfr_mode	 mode;	char			*offset;	es_file_buf		 dummy_write_buf;	/* Ensure that the operation is consistent with the options. */	if ((private->options & ES_OPT_APPEND) == 0) {	    private->status = ES_INCONSISTENT_POS;#ifdef DEBUG	    (void) fprintf(stderr, "es_file_replace: read-only stream\n");#endif	    goto Error_Return;	}	if (private->pos < private->length) {	    if (last_plus_one <= private->length) {		mode = esfr_overwrite;	    } else {		mode = esfr_truncate;		if (count != 0) {		    private->status = ES_INVALID_ARGUMENTS;#ifdef DEBUG		    (void) fprintf(stderr,				  "%s: non-zero (%d) count in truncate\n",				  "es_file_replace", count);#endif		    goto Error_Return;		}		if (private->pos < private->length_on_disk) {		    private->status = ES_INVALID_ARGUMENTS;#ifdef DEBUG		    (void) fprintf(stderr,				  "%s: truncate @ %d when length_on_disk %d\n",				  "es_file_replace", private->pos,				  private->length_on_disk);#endif		    goto Error_Return;		}	    }	    if ((private->options & ES_OPT_OVERWRITE) == 0 ||	        ((mode == esfr_overwrite) &&	         (count != last_plus_one-private->pos))) {		private->status = ES_INVALID_ARGUMENTS;#ifdef DEBUG		(void) fprintf(stderr, "%s last_plus_one is %d, len is %d\n",				"es_file_replace position error:",				last_plus_one, private->length); #endif		goto Error_Return;	    }	} else {	    mode = esfr_insert;	}		/* Do the replace */	if (mode == esfr_truncate) {	    es_file_maybe_truncate_buf(&private->read_buf);	    es_file_maybe_truncate_buf(&private->write_buf);	    *count_used = 0;	} else if (mode == esfr_overwrite) {	    /* If new bytes will fit in the write_buf, position the write_buf	     * to accomodate them (unless there are 4 or fewer bytes) and	     * overwrite.  Otherwise, flush out the write_buf and write	     * the new bytes directly.	     */	    if (count <= WRITE_BUF_LEN) {		if (count < 5 &&		    (last_plus_one < private->write_buf.start ||		     private->pos >= BUF_LAST_PLUS_ONE(&private->write_buf))) {		    goto Write_Direct;		}		if (es_file_move_write_buf(private, private->pos,					   last_plus_one, &offset) < 0) {			goto Error_Return;		}		bcopy(buf, offset, count);		*count_used = count;	    } else {		goto Flush_And_Write_Direct;	    }	} else /* mode == es_insert */ {	    /* Insert only happens at end-of-stream, thus it always increases	     * private->write_buf.used by the size of the insertion.	     * If new bytes will fit in the write_buf, position the write_buf	     * to accomodate them and add them.  Otherwise, flush out the	     * write_buf and write the new bytes directly.	     */	    if (count <= WRITE_BUF_LEN) {		if (es_file_move_write_buf(private, private->pos,					   private->pos+count, &offset) < 0) {			goto Error_Return;		}		bcopy(buf, offset, count);		private->write_buf.used += count;	    } else {Flush_And_Write_Direct:		if (es_file_flush_write_buf(private,					    &private->write_buf) < 0) {			goto Error_Return;		}Write_Direct:		/* Fake up a write buffer */		dummy_write_buf.used = count;		dummy_write_buf.start = private->pos;		dummy_write_buf.chars = buf;		if (es_file_flush_write_buf(private,					    &dummy_write_buf) <= 0) {		    goto Error_Return;		}		/* Correct overlap with the read_buf that is not masked		 * by overlap with the write_buf.		 */		if (private->read_buf.used > 0 &&		    private->pos < BUF_LAST_PLUS_ONE(&private->read_buf) &&		    private->read_buf.start < private->pos+count) {		    /* There is overlap: in future, might be better to update		     * read_buf, but for now, just discard it.		     */		    BUF_INVALIDATE(&private->read_buf);		}	    }	    *count_used = count;	}Return:	private->pos += *count_used;	if (mode != esfr_overwrite) private->length = private->pos;	return(private->pos); Error_Return:	return(ES_CANNOT_SET); } extern intes_file_copy_status(esh, to)	Es_handle	 esh;	char		*to;{	Es_file_data	 private = ABS_TO_REP(esh);	int		 dummy;	return(es_copy_status(to, private->fd, &dummy));}extern Es_handlees_file_make_backup(esh, backup_pattern, status)	register Es_handle	 esh;	char			*backup_pattern;	Es_status		*status;/* Currently backup_pattern must be of the form "%s<suffix>" */{	register Es_file_data	 private;	char			 backup_name[MAXNAMLEN];	int			 fd, len, retrying = FALSE;	Es_status		 dummy_status;	Es_handle		 result;        struct stat stto, stfrom;        struct statfs fs;	if (status == 0)	    status = &dummy_status;	if ((esh == NULL) || (esh->ops != &es_file_ops)) {	    *status = ES_INVALID_HANDLE;	    return(NULL);	}	*status = ES_CHECK_ERRNO;	errno = 0;	private = ABS_TO_REP(esh);#ifdef BACKUP_AT_HEAD_OF_LINK	(void) sprintf(backup_name, backup_pattern, private->name);#else	(void) sprintf(backup_name, backup_pattern,			(private->true_name) ? private->true_name					     : private->name);#endif	fd = private->fd;	len = lseek(fd, 0L, 1);	if (lseek(fd, 0L, 0) != 0)	    goto Lseek_Failed;                if (stat(private->name, &stfrom) < 0) {                   *status = ES_CHECK_ERRNO;                return (ES_NULL);        }        if (stat(backup_name, &stto) < 0 && errno != ENOENT) {                *status = ES_CHECK_ERRNO;                return (ES_NULL);        }        else if (errno == ENOENT) stto.st_size = 0;        if (statfs(private->name, &fs) < 0) {                *status = ES_CHECK_ERRNO;                return (ES_NULL);        }        if (stfrom.st_size - stto.st_size > fs.f_bavail * DEV_BSIZE) {                *status = ES_CHECK_ERRNO;                errno = ENOSPC;                return (ES_NULL);        }Retry:	if (es_copy_fd(private->name, backup_name, fd) != 0) {	    if ((!retrying) && (errno == EACCES)) {		/* It may be that the backup_name is already taken by a file		 * that cannot be overwritten, so try to remove it first.		 */		if (unlink(backup_name) == 0) {		    retrying = TRUE;		    goto Retry;		}		if (errno == ENOENT)		    /* backup_name does not exist, so problem with es_copy_fd		     * really is unfixable access error, which that needs to		     * be reported to caller, so set errno back!		     */		    errno = EACCES;	    }	    return(NULL);	}	if (lseek(fd, (long)len, 0) != len)	    goto Lseek_Failed;	result = es_file_create(backup_name, 0, status);	*status = ES_SUCCESS;	return(result);Lseek_Failed:	*status = ES_SEEK_FAILED;	return(NULL);}

⌨️ 快捷键说明

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