Annotation of src/usr.bin/cvs/entries.c, Revision 1.3
1.1 jfb 1: /* $OpenBSD$ */
2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <sys/param.h>
28: #include <sys/stat.h>
29:
30: #include <stdio.h>
31: #include <fcntl.h>
32: #include <stdlib.h>
33: #include <unistd.h>
34: #include <string.h>
35:
36: #include "log.h"
37: #include "cvs.h"
38:
39:
40: #define CVS_ENTRIES_NFIELDS 5
41: #define CVS_ENTRIES_DELIM '/'
42:
43:
1.3 ! jfb 44:
! 45: static struct cvs_ent* cvs_ent_clone (const struct cvs_ent *);
! 46:
! 47:
! 48:
1.1 jfb 49: /*
50: * cvs_ent_open()
51: *
52: * Open the CVS Entries file for the directory <dir>.
53: * Returns a pointer to the CVSENTRIES file structure on success, or NULL
54: * on failure.
55: */
56:
57: CVSENTRIES*
1.2 jfb 58: cvs_ent_open(const char *dir, int flags)
1.1 jfb 59: {
60: size_t len;
1.3 ! jfb 61: char entpath[MAXPATHLEN], ebuf[128], mode[4];
1.1 jfb 62: FILE *fp;
63: struct cvs_ent *ent;
64: CVSENTRIES *ep;
65:
1.3 ! jfb 66: memset(mode, 0, sizeof(mode));
! 67: if (flags & O_RDONLY)
! 68: mode[0] = 'r';
! 69: else if (flags & O_WRONLY)
! 70: mode[0] = 'w';
! 71: else if (flags & O_RDWR) {
! 72: mode[0] = 'r';
! 73: mode[1] = '+';
! 74: }
! 75:
1.1 jfb 76: snprintf(entpath, sizeof(entpath), "%s/" CVS_PATH_ENTRIES, dir);
1.3 ! jfb 77: fp = fopen(entpath, mode);
1.1 jfb 78: if (fp == NULL) {
79: cvs_log(LP_ERRNO, "cannot open CVS/Entries for reading",
80: entpath);
81: return (NULL);
82: }
83:
84: ep = (CVSENTRIES *)malloc(sizeof(CVSENTRIES));
85: if (ep == NULL) {
86: cvs_log(LP_ERRNO, "failed to allocate Entries data");
87: (void)fclose(fp);
88: return (NULL);
89: }
90: ep->cef_path = strdup(dir);
91: if (ep->cef_path == NULL) {
92: cvs_log(LP_ERRNO, "failed to copy Entries path");
93: free(ep);
94: (void)fclose(fp);
95: return (NULL);
96: }
97:
98: ep->cef_nid = 0;
99: ep->cef_entries = NULL;
100: ep->cef_nbent = 0;
101:
1.3 ! jfb 102: /* only keep a pointer to the open file if we're in writing mode */
! 103: if ((flags & O_WRONLY) || (flags & O_RDWR))
! 104: ep->cef_file = fp;
! 105:
1.1 jfb 106: while (fgets(ebuf, sizeof(ebuf), fp) != NULL) {
107: len = strlen(ebuf);
108: if ((len > 0) && (ebuf[len - 1] == '\n'))
109: ebuf[--len] = '\0';
110: ent = cvs_ent_parse(ebuf);
111: if (ent == NULL)
112: continue;
113:
114: if (cvs_ent_add(ep, ent) < 0) {
115: cvs_ent_close(ep);
116: ep = NULL;
117: break;
118: }
119: }
120:
121: (void)fclose(fp);
122: return (ep);
123: }
124:
125:
126: /*
127: * cvs_ent_close()
128: *
129: * Close the Entries file <ep>.
130: */
131:
132: void
133: cvs_ent_close(CVSENTRIES *ep)
134: {
135: free(ep);
136: }
137:
138:
139: /*
140: * cvs_ent_add()
141: *
1.3 ! jfb 142: * Add the entry <ent> to the Entries file <ef>.
1.1 jfb 143: */
144:
145: int
146: cvs_ent_add(CVSENTRIES *ef, struct cvs_ent *ent)
147: {
148: void *tmp;
1.3 ! jfb 149:
! 150: if (ef->cef_file == NULL) {
! 151: cvs_log(LP_ERR, "Entries file is opened in read-only mode");
! 152: return (-1);
! 153: }
1.1 jfb 154:
155: if (cvs_ent_get(ef, ent->ce_name) != NULL)
156: return (-1);
157:
1.3 ! jfb 158: if (fseek(ef->cef_file, (long)0, SEEK_END) == -1) {
! 159: cvs_log(LP_ERRNO, "failed to seek to end of CVS/Entries file");
1.1 jfb 160: return (-1);
161: }
1.3 ! jfb 162: fprintf(ef->cef_file, "%s\n", ent->ce_line);
! 163:
! 164: tmp = realloc(ef->cef_entries, (ef->cef_nbent + 1) * sizeof(ent));
! 165: if (tmp == NULL) {
! 166: cvs_log(LP_ERRNO, "failed to resize entries buffer");
! 167: return (-1);
! 168: }
! 169:
! 170: ef->cef_entries = (struct cvs_ent **)tmp;
! 171: ef->cef_entries[ef->cef_nbent++] = ent;
! 172:
! 173: return (0);
! 174: }
! 175:
! 176:
! 177: /*
! 178: * cvs_ent_addln()
! 179: *
! 180: * Add a line to the Entries file.
! 181: */
! 182:
! 183: int
! 184: cvs_ent_addln(CVSENTRIES *ef, const char *line)
! 185: {
! 186: void *tmp;
! 187: struct cvs_ent *ent;
! 188:
! 189: if (ef->cef_file == NULL) {
! 190: cvs_log(LP_ERR, "Entries file is opened in read-only mode");
! 191: return (-1);
! 192: }
! 193:
! 194: ent = cvs_ent_parse(line);
! 195: if (ent == NULL)
! 196: return (-1);
! 197:
! 198: if (cvs_ent_get(ef, ent->ce_name) != NULL)
! 199: return (-1);
1.1 jfb 200:
1.3 ! jfb 201: tmp = realloc(ef->cef_entries, (ef->cef_nbent + 1) * sizeof(ent));
1.1 jfb 202: if (tmp == NULL) {
203: cvs_log(LP_ERRNO, "failed to resize entries buffer");
204: return (-1);
205: }
206:
207: ef->cef_entries = (struct cvs_ent **)tmp;
1.3 ! jfb 208: ef->cef_entries[ef->cef_nbent++] = ent;
1.1 jfb 209:
210: return (0);
211: }
212:
213:
214: /*
215: * cvs_ent_get()
216: *
217: * Get the CVS entry from the Entries file <ef> whose 'name' portion matches
218: * <file>.
219: * Returns a pointer to the cvs entry structure on success, or NULL on failure.
220: */
221:
222: struct cvs_ent*
223: cvs_ent_get(CVSENTRIES *ef, const char *file)
224: {
225: u_int i;
226:
227: for (i = 0; i < ef->cef_nbent; i++) {
228: if (strcmp(ef->cef_entries[i]->ce_name, file) == 0)
229: return ef->cef_entries[i];
230: }
231:
232: return (NULL);
233: }
234:
235:
236: /*
237: * cvs_ent_next()
238: *
239: * Returns a pointer to the cvs entry structure on success, or NULL on failure.
240: */
241:
242: struct cvs_ent*
243: cvs_ent_next(CVSENTRIES *ef)
244: {
245: if (ef->cef_nid >= ef->cef_nbent)
246: return (NULL);
247:
248: return (ef->cef_entries[ef->cef_nid++]);
249: }
250:
251:
252: /*
253: * cvs_ent_parse()
254: *
255: * Parse a single line from a CVS/Entries file and return a cvs_entry structure
256: * containing all the parsed information.
257: */
258:
259: struct cvs_ent*
260: cvs_ent_parse(const char *entry)
261: {
262: int i;
263: char *fields[CVS_ENTRIES_NFIELDS], *sp, *dp;
264: struct cvs_ent *entp;
265:
266: entp = (struct cvs_ent *)malloc(sizeof(*entp));
267: if (entp == NULL) {
268: cvs_log(LP_ERRNO, "failed to allocate CVS entry");
269: return (NULL);
270: }
271:
272: entp->ce_rev = rcsnum_alloc();
273: if (entp->ce_rev == NULL) {
274: free(entp);
275: return (NULL);
276: }
277:
278: entp->ce_line = strdup(entry);
279: if (entp->ce_line == NULL) {
280: free(entp);
281: return (NULL);
282: }
283:
284: entp->ce_buf = strdup(entry);
285: if (entp->ce_buf == NULL) {
286: free(entp->ce_line);
287: free(entp);
288: return (NULL);
289: }
290: sp = entp->ce_buf;
291:
292: if (*sp == CVS_ENTRIES_DELIM)
293: entp->ce_type = CVS_ENT_FILE;
294: else if (*sp == 'D') {
295: entp->ce_type = CVS_ENT_DIR;
296: sp++;
297: }
298: else {
299: /* unknown entry, ignore for future expansion */
300: entp->ce_type = CVS_ENT_NONE;
301: sp++;
302: }
303:
304: sp++;
305: i = 0;
306: do {
307: dp = strchr(sp, CVS_ENTRIES_DELIM);
308: if (dp != NULL)
309: *(dp++) = '\0';
310: fields[i++] = sp;
311: sp = dp;
312: } while ((dp != NULL) && (i < CVS_ENTRIES_NFIELDS));
313:
314: entp->ce_name = fields[0];
315:
316: if (entp->ce_type == CVS_ENT_FILE) {
317: rcsnum_aton(fields[1], NULL, entp->ce_rev);
318: entp->ce_timestamp = fields[2];
319: entp->ce_opts = fields[3];
320: entp->ce_tag = fields[4];
321: }
322:
323: return (entp);
324: }