* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $Id: fileupd.c,v 1.1.1.1 1996/12/09 14:05:35 joerg Exp $
*/
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include "pwupd.h"
+int
+extendline(char **buf, int * buflen, int needed)
+{
+ if (needed > *buflen) {
+ char *tmp = realloc(*buf, needed);
+ if (tmp == NULL)
+ return -1;
+ *buf = tmp;
+ *buflen = needed;
+ }
+ return *buflen;
+}
+
+int
+extendarray(char ***buf, int * buflen, int needed)
+{
+ if (needed > *buflen) {
+ char **tmp = realloc(*buf, needed * sizeof(char *));
+ if (tmp == NULL)
+ return -1;
+ *buf = tmp;
+ *buflen = needed;
+ }
+ return *buflen;
+}
+
+
int
fileupdate(char const * filename, mode_t fmode, char const * newline, char const * prefix, int pfxlen, int updmode)
{
- int rc = 0;
+ int rc = 0;
if (pfxlen <= 1)
- errno = EINVAL;
+ rc = EINVAL;
else {
- int infd = open(filename, O_RDWR | O_CREAT | O_EXLOCK, fmode);
+ int infd = open(filename, O_RDWR | O_CREAT, fmode);
- if (infd != -1) {
- FILE *infp = fdopen(infd, "r+");
+ if (infd == -1)
+ rc = errno;
+ else {
+ FILE *infp = fdopen(infd, "r+");
- if (infp == NULL)
+ if (infp == NULL) {
+ rc = errno; /* Assumes fopen(3) sets errno from open(2) */
close(infd);
- else {
- int outfd;
- char file[MAXPATHLEN];
+ } else {
+ int outfd;
+ char file[MAXPATHLEN];
strcpy(file, filename);
strcat(file, ".new");
outfd = open(file, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, fmode);
- if (outfd != -1) {
- FILE *outfp = fdopen(outfd, "w+");
+ if (outfd == -1)
+ rc = errno;
+ else {
+ FILE *outfp = fdopen(outfd, "w+");
- if (outfp == NULL)
+ if (outfp == NULL) {
+ rc = errno;
close(outfd);
- else {
- int updated = UPD_CREATE;
- char line[2048];
-
- while (fgets(line, sizeof(line), infp) != NULL) {
- char *p = strchr(line, '\n');
-
- if (p == NULL) { /* Line too long */
- int ch;
-
- fputs(line, outfp);
- while ((ch = fgetc(infp)) != EOF) {
- fputc(ch, outfp);
- if (ch == '\n')
- break;
+ } else {
+ int updated = UPD_CREATE;
+ int linesize = PWBUFSZ;
+ char *line = malloc(linesize);
+
+ nextline:
+ while (fgets(line, linesize, infp) != NULL) {
+ char *p = strchr(line, '\n');
+
+ while ((p = strchr(line, '\n')) == NULL) {
+ int l;
+ if (extendline(&line, &linesize, linesize + PWBUFSZ) == -1) {
+ int ch;
+ fputs(line, outfp);
+ while ((ch = fgetc(infp)) != EOF) {
+ fputc(ch, outfp);
+ if (ch == '\n')
+ break;
+ }
+ goto nextline;
}
- continue;
+ l = strlen(line);
+ if (fgets(line + l, linesize - l, infp) == NULL)
+ break;
}
if (*line != '#' && *line != '\n') {
if (!updated && strncmp(line, prefix, pfxlen) == 0) {
* then error
*/
if (updmode != updated)
- errno = (updmode == UPD_CREATE) ? EEXIST : ENOENT;
+ /* -1 return means:
+ * update,delete=no user entry
+ * create=entry exists
+ */
+ rc = -1;
else {
/*
/*
* Flush the file and check for the result
*/
- rc = fflush(outfp) != EOF;
- if (rc) {
-
+ if (fflush(outfp) == EOF)
+ rc = errno; /* Failed to update */
+ else {
/*
* Copy data back into the
* original file and truncate
*/
rewind(infp);
rewind(outfp);
- while (fgets(line, sizeof(line), outfp) != NULL)
+ while (fgets(line, linesize, outfp) != NULL)
fputs(line, infp);
/*
+ * If there was a problem with copying
+ * we will just rename 'file.new'
+ * to 'file'.
* This is a gross hack, but we may have
* corrupted the original file
- * Unfortunately, it will lose the inode.
+ * Unfortunately, it will lose the inode
+ * and hence the lock.
*/
if (fflush(infp) == EOF || ferror(infp))
- rc = rename(file, filename) == 0;
+ rename(file, filename);
else
ftruncate(infd, ftell(infp));
}
}
+ free(line);
fclose(outfp);
}
remove(file);