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 |
|