Merge branch 'vendor/GCC44'
[dragonfly.git] / bin / cpdup / fsmid.c
1 /*-
2  * FSMID.C
3  *
4  * (c) Copyright 1997-1999,2006 by Matthew Dillon.  Permission to
5  *     use and distribute based on the FreeBSD copyright.
6  *
7  * $DragonFly: src/bin/cpdup/fsmid.c,v 1.3 2008/11/10 14:30:02 swildner Exp $
8  */
9
10 #include "cpdup.h"
11
12 typedef struct FSMIDNode {
13     struct FSMIDNode *fid_Next;
14     char *fid_Name;
15     int64_t fid_Code;
16     int fid_Accessed;
17 } FSMIDNode;
18
19 static FSMIDNode *fsmid_lookup(const char *sfile);
20 static void fsmid_cache(const char *dpath, int ddirlen);
21
22 static char *FSMIDDCache;       /* cache source directory name */
23 static FSMIDNode *FSMIDBase;
24 static int FSMIDDCacheDirLen;
25 static int FSMIDDCacheDirty;
26
27 void 
28 fsmid_flush(void)
29 {
30     if (FSMIDDCacheDirty && FSMIDDCache) {
31         FILE *fo;
32
33         if ((fo = fopen(FSMIDDCache, "w")) != NULL) {
34             FSMIDNode *node;
35
36             for (node = FSMIDBase; node; node = node->fid_Next) {
37                 if (node->fid_Accessed && node->fid_Code) {
38                     fprintf(fo, "%016jx %zu %s\n", 
39                         (intmax_t)node->fid_Code, 
40                         strlen(node->fid_Name),
41                         node->fid_Name
42                     );
43                 }
44             }
45             fclose(fo);
46         }
47     }
48
49     FSMIDDCacheDirty = 0;
50
51     if (FSMIDDCache) {
52         FSMIDNode *node;
53
54         while ((node = FSMIDBase) != NULL) {
55             FSMIDBase = node->fid_Next;
56
57             if (node->fid_Name)
58                 free(node->fid_Name);
59             free(node);
60         }
61         free(FSMIDDCache);
62         FSMIDDCache = NULL;
63     }
64 }
65
66 static void
67 fsmid_cache(const char *dpath, int ddirlen)
68 {
69     FILE *fi;
70
71     /*
72      * Already cached
73      */
74
75     if (
76         FSMIDDCache &&
77         ddirlen == FSMIDDCacheDirLen &&
78         strncmp(dpath, FSMIDDCache, ddirlen) == 0
79     ) {
80         return;
81     }
82
83     /*
84      * Different cache, flush old cache
85      */
86
87     if (FSMIDDCache != NULL)
88         fsmid_flush();
89
90     /*
91      * Create new cache
92      */
93
94     FSMIDDCacheDirLen = ddirlen;
95     FSMIDDCache = mprintf("%*.*s%s", ddirlen, ddirlen, dpath, FSMIDCacheFile);
96
97     if ((fi = fopen(FSMIDDCache, "r")) != NULL) {
98         FSMIDNode **pnode = &FSMIDBase;
99         int c;
100
101         c = fgetc(fi);
102         while (c != EOF) {
103             FSMIDNode *node = *pnode = malloc(sizeof(FSMIDNode));
104             char *s;
105             int nlen;
106
107             nlen = 0;
108
109             if (pnode == NULL || node == NULL)
110                 fatal("out of memory");
111
112             bzero(node, sizeof(FSMIDNode));
113             node->fid_Code = strtoull(fextract(fi, -1, &c, ' '), NULL, 16);
114             node->fid_Accessed = 1;
115             if ((s = fextract(fi, -1, &c, ' ')) != NULL) {
116                 nlen = strtol(s, NULL, 0);
117                 free(s);
118             }
119             /*
120              * extracting fid_Name - name may contain embedded control 
121              * characters.
122              */
123             CountSourceReadBytes += nlen+1;
124             node->fid_Name = fextract(fi, nlen, &c, EOF);
125             if (c != '\n') {
126                 fprintf(stderr, "Error parsing FSMID Cache: %s (%c)\n", FSMIDDCache, c);
127                 while (c != EOF && c != '\n')
128                     c = fgetc(fi);
129             }
130             if (c != EOF)
131                 c = fgetc(fi);
132             pnode = &node->fid_Next;
133         }
134         fclose(fi);
135     }
136 }
137
138 /*
139  * fsmid_lookup:        lookup/create fsmid entry
140  */
141
142 static FSMIDNode *
143 fsmid_lookup(const char *sfile)
144 {
145     FSMIDNode **pnode;
146     FSMIDNode *node;
147
148     for (pnode = &FSMIDBase; (node = *pnode) != NULL; pnode = &node->fid_Next) {
149         if (strcmp(sfile, node->fid_Name) == 0) {
150             break;
151         }
152     }
153     if (node == NULL) {
154         if ((node = *pnode = malloc(sizeof(FSMIDNode))) == NULL)
155             fatal("out of memory");
156         bzero(node, sizeof(FSMIDNode));
157         node->fid_Name = strdup(sfile);
158         FSMIDDCacheDirty = 1;
159     }
160     node->fid_Accessed = 1;
161     return(node);
162 }
163
164 /*
165  * fsmid_check:  check FSMID against file
166  *
167  *      Return -1 if check failed
168  *      Return 0  if check succeeded
169  *
170  * dpath can be NULL, in which case we are force-updating
171  * the source FSMID.
172  */
173 int
174 fsmid_check(int64_t fsmid, const char *dpath)
175 {
176     const char *dfile;
177     int ddirlen;
178     FSMIDNode *node;
179
180     if ((dfile = strrchr(dpath, '/')) != NULL)
181         ++dfile;
182     else
183         dfile = dpath;
184     ddirlen = dfile - dpath;
185
186     fsmid_cache(dpath, ddirlen);
187
188     node = fsmid_lookup(dfile);
189
190     if (node->fid_Code != fsmid) {
191         node->fid_Code = fsmid;
192         FSMIDDCacheDirty = 1;
193         return(1);
194     }
195     return(0);
196 }
197