lib/libutil/gr_util.c
int
gr_copy(int ffd, int tfd, const struct group *gr, struct group *old_gr)
{
	char buf[8192], *end, *line, *p, *q, *r, t;
	struct group *fgr;
	const struct group *sgr;
	size_t len;
	int eof, readlen;

	sgr = gr;
	if (gr == NULL) {
		line = NULL;
		if (old_gr == NULL)
			return (-1);
		sgr = old_gr;
	} else if ((line = gr_make(gr)) == NULL)
		return (-1);

	eof = 0;
	len = 0;
	p = q = end = buf;
	for (;;) {
		/* find the end of the current line */
		for (p = q; q < end && *q != '\0'; ++q)
			if (*q == '\n')
				break;

		/* if we don't have a complete line, fill up the buffer */
		if (q >= end) {
			if (eof)
				break;
			if ((size_t)(q - p) >= sizeof(buf)) {
				warnx("group line too long");
				errno = EINVAL; /* hack */
				goto err;
			}
			if (p < end) {
				q = memmove(buf, p, end -p);
				end -= p - buf;
			} else {
				p = q = end = buf;
			}
			readlen = read(ffd, end, sizeof(buf) - (end -buf));
			if (readlen == -1)
				goto err;
			else
				len = (size_t)readlen;
			if (len == 0 && p == buf)
				break;
			end += len;
			len = end - buf;
			if (len < (ssize_t)sizeof(buf)) {
				eof = 1;
				if (len > 0 && buf[len -1] != '\n')
					++len, *end++ = '\n';
			}
			continue;
		}

		/* is it a blank line or a comment? */
		for (r = p; r < q && isspace(*r); ++r)
			/* nothing */;
		if (r == q || *r == '#') {
			/* yep */
			if (write(tfd, p, q -p + 1) != q - p + 1)
				goto err;
			++q;
			continue;
		}

		/* is it the one we're looking for? */

		t = *q;
		*q = '\0';

		fgr = gr_scan(r);

		/* fgr is either a struct group for the current line,
		 * or NULL if the line is malformed.
		 */

		*q = t;
		if (fgr == NULL || fgr->gr_gid != sgr->gr_gid) {
			/* nope */
			if (fgr != NULL)
				free(fgr);
			if (write(tfd, p, q - p + 1) != q - p + 1)
				goto err;
			++q;
			continue;
		}
		if (old_gr && !gr_equal(fgr, old_gr)) {
			warnx("entry inconsistent");
			free(fgr);
			errno = EINVAL; /* hack */
			goto err;
		}
		free(fgr);

		/* it is, replace or remove it */
		if (line != NULL) {
			len = strlen(line);
			if (write(tfd, line, len) != (int) len)
				goto err;
		} else {
			/* when removed, avoid the \n */
			q++;
		}
		/* we're done, just copy the rest over */
		for (;;) {
			if (write(tfd, q, end - q) != end - q)
				goto err;
			q = buf;
			readlen = read(ffd, buf, sizeof(buf));
			if (readlen == 0)
				break;
			else
				len = (size_t)readlen;
			if (readlen == -1)
				goto err;
			end = buf + len;
		}
		goto done;
	}

	/* if we got here, we didn't find the old entry */
	if (line == NULL) {
		errno = ENOENT;
		goto err;
	}
	len = strlen(line);
	if ((size_t)write(tfd, line, len) != len ||
	   write(tfd, "\n", 1) != 1)
		goto err;
 done:
	if (line != NULL)
		free(line);
	return (0);
 err:
	if (line != NULL)
		free(line);
	return (-1);
}
/*
 * Copy the group file from one descriptor to another, replacing, deleting
 * or adding a single record on the way.
 */
Copy the group file from one descriptor to another, replacing, deleting
or adding a single record on the way.
Copy the group file from one descriptor to another replacing deleting or adding a single record on the way .
int
gr_copy(int ffd, int tfd, const struct group *gr, struct group *old_gr)
{
	char buf[8192], *end, *line, *p, *q, *r, t;
	struct group *fgr;
	const struct group *sgr;
	size_t len;
	int eof, readlen;
	sgr = gr;
	if (gr == NULL) {
		line = NULL;
		if (old_gr == NULL)
			return (-1);
		sgr = old_gr;
	} else if ((line = gr_make(gr)) == NULL)
		return (-1);
	eof = 0;
	len = 0;
	p = q = end = buf;
	for (;;) {
		for (p = q; q < end && *q != '\0'; ++q)
			if (*q == '\n')
				break;
		if (q >= end) {
			if (eof)
				break;
			if ((size_t)(q - p) >= sizeof(buf)) {
				warnx("group line too long");
				errno = EINVAL; 
				goto err;
			}
			if (p < end) {
				q = memmove(buf, p, end -p);
				end -= p - buf;
			} else {
				p = q = end = buf;
			}
			readlen = read(ffd, end, sizeof(buf) - (end -buf));
			if (readlen == -1)
				goto err;
			else
				len = (size_t)readlen;
			if (len == 0 && p == buf)
				break;
			end += len;
			len = end - buf;
			if (len < (ssize_t)sizeof(buf)) {
				eof = 1;
				if (len > 0 && buf[len -1] != '\n')
					++len, *end++ = '\n';
			}
			continue;
		}
		for (r = p; r < q && isspace(*r); ++r)
			;
		if (r == q || *r == '#') {
			if (write(tfd, p, q -p + 1) != q - p + 1)
				goto err;
			++q;
			continue;
		}
		t = *q;
		*q = '\0';
		fgr = gr_scan(r);
		*q = t;
		if (fgr == NULL || fgr->gr_gid != sgr->gr_gid) {
			if (fgr != NULL)
				free(fgr);
			if (write(tfd, p, q - p + 1) != q - p + 1)
				goto err;
			++q;
			continue;
		}
		if (old_gr && !gr_equal(fgr, old_gr)) {
			warnx("entry inconsistent");
			free(fgr);
			errno = EINVAL; 
			goto err;
		}
		free(fgr);
		if (line != NULL) {
			len = strlen(line);
			if (write(tfd, line, len) != (int) len)
				goto err;
		} else {
			q++;
		}
		for (;;) {
			if (write(tfd, q, end - q) != end - q)
				goto err;
			q = buf;
			readlen = read(ffd, buf, sizeof(buf));
			if (readlen == 0)
				break;
			else
				len = (size_t)readlen;
			if (readlen == -1)
				goto err;
			end = buf + len;
		}
		goto done;
	}
	if (line == NULL) {
		errno = ENOENT;
		goto err;
	}
	len = strlen(line);
	if ((size_t)write(tfd, line, len) != len ||
	   write(tfd, "\n", 1) != 1)
		goto err;
 done:
	if (line != NULL)
		free(line);
	return (0);
 err:
	if (line != NULL)
		free(line);
	return (-1);
}
int gr_copy ( int ffd , int tfd , const struct group * gr , struct group * old_gr ) { char buf [ 8192 ] , * end , * line , * p , * q , * r , t ; struct group * fgr ; const struct group * sgr ; size_t len ; int eof , readlen ; sgr = gr ; if ( gr == NULL ) { line = NULL ; if ( old_gr == NULL ) return ( -1 ) ; sgr = old_gr ; } else if ( ( line = gr_make ( gr ) ) == NULL ) return ( -1 ) ; eof = 0 ; len = 0 ; p = q = end = buf ; for ( ; ; ) { for ( p = q ; q < end && * q != ' \0 ' ; ++ q ) if ( * q == ' \n ' ) break ; if ( q >= end ) { if ( eof ) break ; if ( ( size_t ) ( q - p ) >= sizeof ( buf ) ) { warnx ( " " ) ; errno = EINVAL ; goto err ; } if ( p < end ) { q = memmove ( buf , p , end - p ) ; end -= p - buf ; } else { p = q = end = buf ; } readlen = read ( ffd , end , sizeof ( buf ) - ( end - buf ) ) ; if ( readlen == -1 ) goto err ; else len = ( size_t ) readlen ; if ( len == 0 && p == buf ) break ; end += len ; len = end - buf ; if ( len < ( ssize_t ) sizeof ( buf ) ) { eof = 1 ; if ( len > 0 && buf [ len - 1 ] != ' \n ' ) ++ len , * end ++ = ' \n ' ; } continue ; } for ( r = p ; r < q && isspace ( * r ) ; ++ r ) ; if ( r == q || * r == ' ' ) { if ( write ( tfd , p , q - p + 1 ) != q - p + 1 ) goto err ; ++ q ; continue ; } t = * q ; * q = ' \0 ' ; fgr = gr_scan ( r ) ; * q = t ; if ( fgr == NULL || fgr -> gr_gid != sgr -> gr_gid ) { if ( fgr != NULL ) free ( fgr ) ; if ( write ( tfd , p , q - p + 1 ) != q - p + 1 ) goto err ; ++ q ; continue ; } if ( old_gr && ! gr_equal ( fgr , old_gr ) ) { warnx ( " " ) ; free ( fgr ) ; errno = EINVAL ; goto err ; } free ( fgr ) ; if ( line != NULL ) { len = strlen ( line ) ; if ( write ( tfd , line , len ) != ( int ) len ) goto err ; } else { q ++ ; } for ( ; ; ) { if ( write ( tfd , q , end - q ) != end - q ) goto err ; q = buf ; readlen = read ( ffd , buf , sizeof ( buf ) ) ; if ( readlen == 0 ) break ; else len = ( size_t ) readlen ; if ( readlen == -1 ) goto err ; end = buf + len ; } goto done ; } if ( line == NULL ) { errno = ENOENT ; goto err ; } len = strlen ( line ) ; if ( ( size_t ) write ( tfd , line , len ) != len || write ( tfd , " \n " , 1 ) != 1 ) goto err ; done : if ( line != NULL ) free ( line ) ; return ( 0 ) ; err : if ( line != NULL ) free ( line ) ; return ( -1 ) ; }
Copy the group file from one descriptor to another, replacing, deleting
 or adding a single record on the way.
Copy the group file from one descriptor to another replacing deleting or adding a single record on the way .
/* find the end of the current line */ /* if we don't have a complete line, fill up the buffer */ /* hack */ /* is it a blank line or a comment? */ /* nothing */ /* yep */ /* is it the one we're looking for? */ /* fgr is either a struct group for the current line,
		 * or NULL if the line is malformed.
		 */ /* nope */ /* hack */ /* it is, replace or remove it */ /* when removed, avoid the \n */ /* we're done, just copy the rest over */ /* if we got here, we didn't find the old entry */