Annotation of src/usr.bin/cvs/entries.c, Revision 1.1.1.1
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:
44: /*
45: * cvs_ent_open()
46: *
47: * Open the CVS Entries file for the directory <dir>.
48: * Returns a pointer to the CVSENTRIES file structure on success, or NULL
49: * on failure.
50: */
51:
52: CVSENTRIES*
53: cvs_ent_open(const char *dir)
54: {
55: size_t len;
56: char entpath[MAXPATHLEN], ebuf[128];
57: FILE *fp;
58: struct cvs_ent *ent;
59: CVSENTRIES *ep;
60:
61: snprintf(entpath, sizeof(entpath), "%s/" CVS_PATH_ENTRIES, dir);
62: fp = fopen(entpath, "r");
63: if (fp == NULL) {
64: cvs_log(LP_ERRNO, "cannot open CVS/Entries for reading",
65: entpath);
66: return (NULL);
67: }
68:
69: ep = (CVSENTRIES *)malloc(sizeof(CVSENTRIES));
70: if (ep == NULL) {
71: cvs_log(LP_ERRNO, "failed to allocate Entries data");
72: (void)fclose(fp);
73: return (NULL);
74: }
75: ep->cef_path = strdup(dir);
76: if (ep->cef_path == NULL) {
77: cvs_log(LP_ERRNO, "failed to copy Entries path");
78: free(ep);
79: (void)fclose(fp);
80: return (NULL);
81: }
82:
83: ep->cef_nid = 0;
84: ep->cef_entries = NULL;
85: ep->cef_nbent = 0;
86:
87: while (fgets(ebuf, sizeof(ebuf), fp) != NULL) {
88: len = strlen(ebuf);
89: if ((len > 0) && (ebuf[len - 1] == '\n'))
90: ebuf[--len] = '\0';
91: ent = cvs_ent_parse(ebuf);
92: if (ent == NULL)
93: continue;
94:
95: if (cvs_ent_add(ep, ent) < 0) {
96: cvs_ent_close(ep);
97: ep = NULL;
98: break;
99: }
100: }
101:
102: (void)fclose(fp);
103: return (ep);
104: }
105:
106:
107: /*
108: * cvs_ent_close()
109: *
110: * Close the Entries file <ep>.
111: */
112:
113: void
114: cvs_ent_close(CVSENTRIES *ep)
115: {
116: free(ep);
117: }
118:
119:
120: /*
121: * cvs_ent_add()
122: *
123: * Add the entry <ent>
124: */
125:
126: int
127: cvs_ent_add(CVSENTRIES *ef, struct cvs_ent *ent)
128: {
129: void *tmp;
130: struct cvs_ent *entp;
131:
132: if (cvs_ent_get(ef, ent->ce_name) != NULL)
133: return (-1);
134:
135: entp = cvs_ent_parse(ent->ce_line);
136: if (entp == NULL) {
137: return (-1);
138: }
139:
140: tmp = realloc(ef->cef_entries, (ef->cef_nbent + 1) * sizeof(entp));
141: if (tmp == NULL) {
142: cvs_log(LP_ERRNO, "failed to resize entries buffer");
143: return (-1);
144: }
145:
146: ef->cef_entries = (struct cvs_ent **)tmp;
147: ef->cef_entries[ef->cef_nbent++] = entp;
148:
149: return (0);
150: }
151:
152:
153: /*
154: * cvs_ent_get()
155: *
156: * Get the CVS entry from the Entries file <ef> whose 'name' portion matches
157: * <file>.
158: * Returns a pointer to the cvs entry structure on success, or NULL on failure.
159: */
160:
161: struct cvs_ent*
162: cvs_ent_get(CVSENTRIES *ef, const char *file)
163: {
164: u_int i;
165:
166: for (i = 0; i < ef->cef_nbent; i++) {
167: if (strcmp(ef->cef_entries[i]->ce_name, file) == 0)
168: return ef->cef_entries[i];
169: }
170:
171: return (NULL);
172: }
173:
174:
175: /*
176: * cvs_ent_next()
177: *
178: * Returns a pointer to the cvs entry structure on success, or NULL on failure.
179: */
180:
181: struct cvs_ent*
182: cvs_ent_next(CVSENTRIES *ef)
183: {
184: if (ef->cef_nid >= ef->cef_nbent)
185: return (NULL);
186:
187: return (ef->cef_entries[ef->cef_nid++]);
188: }
189:
190:
191: /*
192: * cvs_ent_parse()
193: *
194: * Parse a single line from a CVS/Entries file and return a cvs_entry structure
195: * containing all the parsed information.
196: */
197:
198: struct cvs_ent*
199: cvs_ent_parse(const char *entry)
200: {
201: int i;
202: char *fields[CVS_ENTRIES_NFIELDS], *sp, *dp;
203: struct cvs_ent *entp;
204:
205: entp = (struct cvs_ent *)malloc(sizeof(*entp));
206: if (entp == NULL) {
207: cvs_log(LP_ERRNO, "failed to allocate CVS entry");
208: return (NULL);
209: }
210:
211: entp->ce_rev = rcsnum_alloc();
212: if (entp->ce_rev == NULL) {
213: free(entp);
214: return (NULL);
215: }
216:
217: entp->ce_line = strdup(entry);
218: if (entp->ce_line == NULL) {
219: free(entp);
220: return (NULL);
221: }
222:
223: entp->ce_buf = strdup(entry);
224: if (entp->ce_buf == NULL) {
225: free(entp->ce_line);
226: free(entp);
227: return (NULL);
228: }
229: sp = entp->ce_buf;
230:
231: if (*sp == CVS_ENTRIES_DELIM)
232: entp->ce_type = CVS_ENT_FILE;
233: else if (*sp == 'D') {
234: entp->ce_type = CVS_ENT_DIR;
235: sp++;
236: }
237: else {
238: /* unknown entry, ignore for future expansion */
239: entp->ce_type = CVS_ENT_NONE;
240: sp++;
241: }
242:
243: sp++;
244: i = 0;
245: do {
246: dp = strchr(sp, CVS_ENTRIES_DELIM);
247: if (dp != NULL)
248: *(dp++) = '\0';
249: fields[i++] = sp;
250: sp = dp;
251: } while ((dp != NULL) && (i < CVS_ENTRIES_NFIELDS));
252:
253: entp->ce_name = fields[0];
254:
255: if (entp->ce_type == CVS_ENT_FILE) {
256: rcsnum_aton(fields[1], NULL, entp->ce_rev);
257: entp->ce_timestamp = fields[2];
258: entp->ce_opts = fields[3];
259: entp->ce_tag = fields[4];
260: }
261:
262: return (entp);
263: }