Deleted Added
full compact
hardlink.c (34461) hardlink.c (44852)
1/* This program is free software; you can redistribute it and/or modify
2 it under the terms of the GNU General Public License as published by
3 the Free Software Foundation; either version 2, or (at your option)
4 any later version.
5
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

--- 27 unchanged lines hidden (view full) ---

36
37/* TODO: change this to something with a marginal degree of
38 efficiency, like maybe a hash table. Yeah. */
39
40List *hardlist; /* Record hardlink information for working files */
41char *working_dir; /* The top-level working directory, used for
42 constructing full pathnames. */
43
1/* This program is free software; you can redistribute it and/or modify
2 it under the terms of the GNU General Public License as published by
3 the Free Software Foundation; either version 2, or (at your option)
4 any later version.
5
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

--- 27 unchanged lines hidden (view full) ---

36
37/* TODO: change this to something with a marginal degree of
38 efficiency, like maybe a hash table. Yeah. */
39
40List *hardlist; /* Record hardlink information for working files */
41char *working_dir; /* The top-level working directory, used for
42 constructing full pathnames. */
43
44/* For check_link_proc: list all of the files named in an inode list. */
45static int
46list_files_proc (node, vstrp)
47 Node *node;
48 void *vstrp;
49{
50 char **strp, *file;
51 int len;
52
53 /* Get the file's basename. This is because -- VERY IMPORTANT --
54 the `hardlinks' field is presently defined only to include links
55 within a directory. So the hardlinks field might be `foo' or
56 `mumble grump flink', but not `foo bar com/baz' or `wham ../bam
57 ../thank/you'. Someday it would be nice to extend this to
58 permit cross-directory links, but the issues involved are
59 hideous. */
60
61 file = strrchr (node->key, '/');
62 if (file)
63 ++file;
64 else
65 file = node->key;
66
67 /* Is it safe to cast vstrp to (char **) here, and then play with
68 the contents? I think so, since vstrp will have started out
69 a char ** to begin with, so we should not have alignment bugs. */
70 strp = (char **) vstrp;
71 len = (*strp == NULL ? 0 : strlen (*strp));
72 *strp = (char *) xrealloc (*strp, len + strlen (file) + 2);
73 if (*strp == NULL)
74 {
75 error (0, errno, "could not allocate memory");
76 return 1;
77 }
78 if (sprintf (*strp + len, "%s ", file) < 0)
79 {
80 error (0, errno, "could not compile file list");
81 return 1;
82 }
83
84 return 0;
85}
86
87/* Set the link field of each hardlink_info node to `data', which is a
88 list of linked files. */
89static int
90set_hardlink_field_proc (node, data)
91 Node *node;
92 void *data;
93{
94 struct hardlink_info *hlinfo = (struct hardlink_info *) node->data;
95 hlinfo->links = xstrdup ((char *) data);
96
97 return 0;
98}
99
100/* For each file being checked in, compile a list of the files linked
101 to it, and cache the list in the file's hardlink_info field. */
102int
103cache_hardlinks_proc (node, data)
104 Node *node;
105 void *data;
106{
107 List *inode_links;
108 char *p, *linked_files = NULL;
109 int err;
110
111 inode_links = (List *) node->data;
112
113 /* inode->data is a list of hardlink_info structures: all the
114 files linked to this inode. We compile a string of each file
115 named in this list, in alphabetical order, separated by spaces.
116 Then store this string in the `links' field of each
117 hardlink_info structure, so that RCS_checkin can easily add
118 it to the `hardlinks' field of a new delta node. */
119
120 sortlist (inode_links, fsortcmp);
121 err = walklist (inode_links, list_files_proc, &linked_files);
122 if (err)
123 return err;
124
125 /* Trim trailing whitespace. */
126 p = linked_files + strlen(linked_files) - 1;
127 while (p > linked_files && isspace (*p))
128 *p-- = '\0';
129
130 err = walklist (inode_links, set_hardlink_field_proc, linked_files);
131 return err;
132}
133
134/* Return a pointer to FILEPATH's node in the hardlist. This means
135 looking up its inode, retrieving the list of files linked to that
136 inode, and then looking up FILE in that list. If the file doesn't
137 seem to exist, return NULL. */
138Node *
139lookup_file_by_inode (filepath)
140 const char *filepath;
141{

--- 90 unchanged lines hidden (view full) ---

232 error (1, 0, "lost hardlink info for %s", file);
233 }
234
235 if (n->data == NULL)
236 n->data = (char *) xmalloc (sizeof (struct hardlink_info));
237 hlinfo = (struct hardlink_info *) n->data;
238 hlinfo->status = T_UPTODATE;
239 hlinfo->checked_out = 1;
44/* Return a pointer to FILEPATH's node in the hardlist. This means
45 looking up its inode, retrieving the list of files linked to that
46 inode, and then looking up FILE in that list. If the file doesn't
47 seem to exist, return NULL. */
48Node *
49lookup_file_by_inode (filepath)
50 const char *filepath;
51{

--- 90 unchanged lines hidden (view full) ---

142 error (1, 0, "lost hardlink info for %s", file);
143 }
144
145 if (n->data == NULL)
146 n->data = (char *) xmalloc (sizeof (struct hardlink_info));
147 hlinfo = (struct hardlink_info *) n->data;
148 hlinfo->status = T_UPTODATE;
149 hlinfo->checked_out = 1;
240 hlinfo->links = NULL;
241}
242
150}
151
243/* Return a string listing all the files known to be linked to FILE in
152/* Return a List with all the files known to be linked to FILE in
244 the working directory. Used by special_file_mismatch, to determine
153 the working directory. Used by special_file_mismatch, to determine
245 whether it is safe to merge two files. */
246char *
247list_files_linked_to (file)
248 const char *file;
154 whether it is safe to merge two files.
155
156 FIXME: What is the memory allocation for the return value? We seem
157 to sometimes allocate a new list (getlist() call below) and sometimes
158 return an existing list (where we return n->data). */
159List *
160list_linked_files_on_disk (file)
161 char *file;
249{
162{
250 char *inodestr, *filelist, *path;
163 char *inodestr, *path;
251 struct stat sb;
252 Node *n;
164 struct stat sb;
165 Node *n;
253 int err;
254
255 /* If hardlist is NULL, we have not been doing an operation that
256 would permit us to know anything about the file's hardlinks
166
167 /* If hardlist is NULL, we have not been doing an operation that
168 would permit us to know anything about the file's hardlinks
257 (cvs update, cvs commit, etc). Return an empty string. */
169 (cvs update, cvs commit, etc). Return an empty list. */
258 if (hardlist == NULL)
170 if (hardlist == NULL)
259 return xstrdup ("");
171 return getlist();
260
261 /* Get the full pathname of file (assuming the working directory) */
262 if (file[0] == '/')
263 path = xstrdup (file);
264 else
265 {
266 char *dir = xgetwd();
267 path = (char *) xmalloc (sizeof(char) *

--- 15 unchanged lines hidden (view full) ---

283 each byte of the inode number. */
284 inodestr = (char *) xmalloc (2*sizeof(ino_t)*sizeof(char) + 1);
285 sprintf (inodestr, "%lx", (unsigned long) sb.st_ino);
286
287 /* Make sure the files linked to this inode are sorted. */
288 n = findnode (hardlist, inodestr);
289 sortlist ((List *) n->data, fsortcmp);
290
172
173 /* Get the full pathname of file (assuming the working directory) */
174 if (file[0] == '/')
175 path = xstrdup (file);
176 else
177 {
178 char *dir = xgetwd();
179 path = (char *) xmalloc (sizeof(char) *

--- 15 unchanged lines hidden (view full) ---

195 each byte of the inode number. */
196 inodestr = (char *) xmalloc (2*sizeof(ino_t)*sizeof(char) + 1);
197 sprintf (inodestr, "%lx", (unsigned long) sb.st_ino);
198
199 /* Make sure the files linked to this inode are sorted. */
200 n = findnode (hardlist, inodestr);
201 sortlist ((List *) n->data, fsortcmp);
202
291 filelist = NULL;
292 err = walklist ((List *) n->data, list_files_proc, &filelist);
293 if (err)
294 error (1, 0, "cannot get list of hardlinks for %s", file);
295
296 free (inodestr);
203 free (inodestr);
297 return filelist;
204 return (List *) n->data;
298}
205}
206
207/* Compare the files in the `key' fields of two lists, returning 1 if
208 the lists are equivalent and 0 otherwise.
209
210 Only the basenames of each file are compared. This is an awful hack
211 that exists because list_linked_files_on_disk returns full paths
212 and the `hardlinks' structure of a RCSVers node contains only
213 basenames. That in turn is a result of the awful hack that only
214 basenames are stored in the RCS file. If anyone ever solves the
215 problem of correctly managing cross-directory hardlinks, this
216 function (along with most functions in this file) must be fixed. */
217
218int
219compare_linkage_lists (links1, links2)
220 List *links1;
221 List *links2;
222{
223 Node *n1, *n2;
224 char *p1, *p2;
225
226 sortlist (links1, fsortcmp);
227 sortlist (links2, fsortcmp);
228
229 n1 = links1->list->next;
230 n2 = links2->list->next;
231
232 while (n1 != links1->list && n2 != links2->list)
233 {
234 /* Get the basenames of both files. */
235 p1 = strrchr (n1->key, '/');
236 if (p1 == NULL)
237 p1 = n1->key;
238 else
239 ++p1;
240
241 p2 = strrchr (n2->key, '/');
242 if (p2 == NULL)
243 p2 = n2->key;
244 else
245 ++p2;
246
247 /* Compare the files' basenames. */
248 if (strcmp (p1, p2) != 0)
249 return 0;
250
251 n1 = n1->next;
252 n2 = n2->next;
253 }
254
255 /* At this point we should be at the end of both lists; if not,
256 one file has more links than the other, and return 1. */
257 return (n1 == links1->list && n2 == links2->list);
258}
259
260/* Find a checked-out file in a list of filenames. Used by RCS_checkout
261 when checking out a new hardlinked file, to decide whether this file
262 can be linked to any others that already exist. The return value
263 is not currently used. */
264
265int
266find_checkedout_proc (node, data)
267 Node *node;
268 void *data;
269{
270 Node **uptodate = (Node **) data;
271 Node *link;
272 char *dir = xgetwd();
273 char *path;
274 struct hardlink_info *hlinfo;
275
276 /* If we have already found a file, don't do anything. */
277 if (*uptodate != NULL)
278 return 0;
279
280 /* Look at this file in the hardlist and see whether the checked_out
281 field is 1, meaning that it has been checked out during this CVS run. */
282 path = (char *)
283 xmalloc (sizeof(char) * (strlen (dir) + strlen (node->key) + 2));
284 sprintf (path, "%s/%s", dir, node->key);
285 link = lookup_file_by_inode (path);
286 free (path);
287 free (dir);
288
289 if (link == NULL)
290 {
291 /* We haven't seen this file -- maybe it hasn't been checked
292 out yet at all. */
293 return 0;
294 }
295
296 hlinfo = (struct hardlink_info *) link->data;
297 if (hlinfo->checked_out)
298 {
299 /* This file has been checked out recently, so it's safe to
300 link to it. */
301 *uptodate = link;
302 }
303
304 return 0;
305}
306