Merge from vendor branch OPENSSH:
[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.1 2006/04/25 21:30:45 dillon 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, "%016llx %d %s\n", 
39                         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                 fprintf(stderr, "out of memory\n");
111                 exit(EXIT_FAILURE);
112             }
113
114             bzero(node, sizeof(FSMIDNode));
115             node->fid_Code = strtoull(fextract(fi, -1, &c, ' '), NULL, 16);
116             node->fid_Accessed = 1;
117             if ((s = fextract(fi, -1, &c, ' ')) != NULL) {
118                 nlen = strtol(s, NULL, 0);
119                 free(s);
120             }
121             /*
122              * extracting fid_Name - name may contain embedded control 
123              * characters.
124              */
125             CountReadBytes += nlen+1;
126             node->fid_Name = fextract(fi, nlen, &c, EOF);
127             if (c != '\n') {
128                 fprintf(stderr, "Error parsing FSMID Cache: %s (%c)\n", FSMIDDCache, c);
129                 while (c != EOF && c != '\n')
130                     c = fgetc(fi);
131             }
132             if (c != EOF)
133                 c = fgetc(fi);
134             pnode = &node->fid_Next;
135         }
136         fclose(fi);
137     }
138 }
139
140 /*
141  * fsmid_lookup:        lookup/create fsmid entry
142  */
143
144 static FSMIDNode *
145 fsmid_lookup(const char *sfile)
146 {
147     FSMIDNode **pnode;
148     FSMIDNode *node;
149
150     for (pnode = &FSMIDBase; (node = *pnode) != NULL; pnode = &node->fid_Next) {
151         if (strcmp(sfile, node->fid_Name) == 0) {
152             break;
153         }
154     }
155     if (node == NULL) {
156         if ((node = *pnode = malloc(sizeof(FSMIDNode))) == NULL) {
157                 fprintf(stderr,"out of memory\n");
158                 exit(EXIT_FAILURE);
159         }
160         bzero(node, sizeof(FSMIDNode));
161         node->fid_Name = strdup(sfile);
162         FSMIDDCacheDirty = 1;
163     }
164     node->fid_Accessed = 1;
165     return(node);
166 }
167
168 /*
169  * fsmid_check:  check FSMID against file
170  *
171  *      Return -1 if check failed
172  *      Return 0  if check succeeded
173  *
174  * dpath can be NULL, in which case we are force-updating
175  * the source FSMID.
176  */
177 int
178 fsmid_check(int64_t fsmid, const char *dpath)
179 {
180     const char *dfile;
181     int ddirlen;
182     int r;
183     FSMIDNode *node;
184
185     r = -1;
186
187     if ((dfile = strrchr(dpath, '/')) != NULL)
188         ++dfile;
189     else
190         dfile = dpath;
191     ddirlen = dfile - dpath;
192
193     fsmid_cache(dpath, ddirlen);
194
195     node = fsmid_lookup(dfile);
196
197     if (node->fid_Code != fsmid) {
198         node->fid_Code = fsmid;
199         FSMIDDCacheDirty = 1;
200         return(1);
201     }
202     return(0);
203 }
204