1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)utilities.c 5.6 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 #include "restore.h" 13 14 /* 15 * Insure that all the components of a pathname exist. 16 */ 17 pathcheck(name) 18 char *name; 19 { 20 register char *cp; 21 struct entry *ep; 22 char *start; 23 24 start = index(name, '/'); 25 if (start == 0) 26 return; 27 for (cp = start; *cp != '\0'; cp++) { 28 if (*cp != '/') 29 continue; 30 *cp = '\0'; 31 ep = lookupname(name); 32 if (ep == NIL) { 33 ep = addentry(name, psearch(name), NODE); 34 newnode(ep); 35 } 36 ep->e_flags |= NEW|KEEP; 37 *cp = '/'; 38 } 39 } 40 41 /* 42 * Change a name to a unique temporary name. 43 */ 44 mktempname(ep) 45 register struct entry *ep; 46 { 47 char oldname[MAXPATHLEN]; 48 49 if (ep->e_flags & TMPNAME) 50 badentry(ep, "mktempname: called with TMPNAME"); 51 ep->e_flags |= TMPNAME; 52 (void) strcpy(oldname, myname(ep)); 53 freename(ep->e_name); 54 ep->e_name = savename(gentempname(ep)); 55 ep->e_namlen = strlen(ep->e_name); 56 renameit(oldname, myname(ep)); 57 } 58 59 /* 60 * Generate a temporary name for an entry. 61 */ 62 char * 63 gentempname(ep) 64 struct entry *ep; 65 { 66 static char name[MAXPATHLEN]; 67 struct entry *np; 68 long i = 0; 69 70 for (np = lookupino(ep->e_ino); np != NIL && np != ep; np = np->e_links) 71 i++; 72 if (np == NIL) 73 badentry(ep, "not on ino list"); 74 (void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino); 75 return (name); 76 } 77 78 /* 79 * Rename a file or directory. 80 */ 81 renameit(from, to) 82 char *from, *to; 83 { 84 if (!Nflag && rename(from, to) < 0) { 85 fprintf(stderr, "Warning: cannot rename %s to %s", from, to); 86 (void) fflush(stderr); 87 perror(""); 88 return; 89 } 90 vprintf(stdout, "rename %s to %s\n", from, to); 91 } 92 93 /* 94 * Create a new node (directory). 95 */ 96 newnode(np) 97 struct entry *np; 98 { 99 char *cp; 100 101 if (np->e_type != NODE) 102 badentry(np, "newnode: not a node"); 103 cp = myname(np); 104 if (!Nflag && mkdir(cp, 0777) < 0) { 105 np->e_flags |= EXISTED; 106 fprintf(stderr, "Warning: "); 107 (void) fflush(stderr); 108 perror(cp); 109 return; 110 } 111 vprintf(stdout, "Make node %s\n", cp); 112 } 113 114 /* 115 * Remove an old node (directory). 116 */ 117 removenode(ep) 118 register struct entry *ep; 119 { 120 char *cp; 121 122 if (ep->e_type != NODE) 123 badentry(ep, "removenode: not a node"); 124 if (ep->e_entries != NIL) 125 badentry(ep, "removenode: non-empty directory"); 126 ep->e_flags |= REMOVED; 127 ep->e_flags &= ~TMPNAME; 128 cp = myname(ep); 129 if (!Nflag && rmdir(cp) < 0) { 130 fprintf(stderr, "Warning: "); 131 (void) fflush(stderr); 132 perror(cp); 133 return; 134 } 135 vprintf(stdout, "Remove node %s\n", cp); 136 } 137 138 /* 139 * Remove a leaf. 140 */ 141 removeleaf(ep) 142 register struct entry *ep; 143 { 144 char *cp; 145 146 if (ep->e_type != LEAF) 147 badentry(ep, "removeleaf: not a leaf"); 148 ep->e_flags |= REMOVED; 149 ep->e_flags &= ~TMPNAME; 150 cp = myname(ep); 151 if (!Nflag && unlink(cp) < 0) { 152 fprintf(stderr, "Warning: "); 153 (void) fflush(stderr); 154 perror(cp); 155 return; 156 } 157 vprintf(stdout, "Remove leaf %s\n", cp); 158 } 159 160 /* 161 * Create a link. 162 */ 163 linkit(existing, new, type) 164 char *existing, *new; 165 int type; 166 { 167 168 if (type == SYMLINK) { 169 if (!Nflag && symlink(existing, new) < 0) { 170 fprintf(stderr, 171 "Warning: cannot create symbolic link %s->%s: ", 172 new, existing); 173 (void) fflush(stderr); 174 perror(""); 175 return (FAIL); 176 } 177 } else if (type == HARDLINK) { 178 if (!Nflag && link(existing, new) < 0) { 179 fprintf(stderr, 180 "Warning: cannot create hard link %s->%s: ", 181 new, existing); 182 (void) fflush(stderr); 183 perror(""); 184 return (FAIL); 185 } 186 } else { 187 panic("linkit: unknown type %d\n", type); 188 return (FAIL); 189 } 190 vprintf(stdout, "Create %s link %s->%s\n", 191 type == SYMLINK ? "symbolic" : "hard", new, existing); 192 return (GOOD); 193 } 194 195 /* 196 * find lowest number file (above "start") that needs to be extracted 197 */ 198 ino_t 199 lowerbnd(start) 200 ino_t start; 201 { 202 register struct entry *ep; 203 204 for ( ; start < maxino; start++) { 205 ep = lookupino(start); 206 if (ep == NIL || ep->e_type == NODE) 207 continue; 208 if (ep->e_flags & (NEW|EXTRACT)) 209 return (start); 210 } 211 return (start); 212 } 213 214 /* 215 * find highest number file (below "start") that needs to be extracted 216 */ 217 ino_t 218 upperbnd(start) 219 ino_t start; 220 { 221 register struct entry *ep; 222 223 for ( ; start > ROOTINO; start--) { 224 ep = lookupino(start); 225 if (ep == NIL || ep->e_type == NODE) 226 continue; 227 if (ep->e_flags & (NEW|EXTRACT)) 228 return (start); 229 } 230 return (start); 231 } 232 233 /* 234 * report on a badly formed entry 235 */ 236 badentry(ep, msg) 237 register struct entry *ep; 238 char *msg; 239 { 240 241 fprintf(stderr, "bad entry: %s\n", msg); 242 fprintf(stderr, "name: %s\n", myname(ep)); 243 fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 244 if (ep->e_sibling != NIL) 245 fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 246 if (ep->e_entries != NIL) 247 fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 248 if (ep->e_links != NIL) 249 fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 250 if (ep->e_next != NIL) 251 fprintf(stderr, "next hashchain name: %s\n", myname(ep->e_next)); 252 fprintf(stderr, "entry type: %s\n", 253 ep->e_type == NODE ? "NODE" : "LEAF"); 254 fprintf(stderr, "inode number: %ld\n", ep->e_ino); 255 panic("flags: %s\n", flagvalues(ep)); 256 } 257 258 /* 259 * Construct a string indicating the active flag bits of an entry. 260 */ 261 char * 262 flagvalues(ep) 263 register struct entry *ep; 264 { 265 static char flagbuf[BUFSIZ]; 266 267 (void) strcpy(flagbuf, "|NIL"); 268 flagbuf[0] = '\0'; 269 if (ep->e_flags & REMOVED) 270 (void) strcat(flagbuf, "|REMOVED"); 271 if (ep->e_flags & TMPNAME) 272 (void) strcat(flagbuf, "|TMPNAME"); 273 if (ep->e_flags & EXTRACT) 274 (void) strcat(flagbuf, "|EXTRACT"); 275 if (ep->e_flags & NEW) 276 (void) strcat(flagbuf, "|NEW"); 277 if (ep->e_flags & KEEP) 278 (void) strcat(flagbuf, "|KEEP"); 279 if (ep->e_flags & EXISTED) 280 (void) strcat(flagbuf, "|EXISTED"); 281 return (&flagbuf[1]); 282 } 283 284 /* 285 * Check to see if a name is on a dump tape. 286 */ 287 ino_t 288 dirlookup(name) 289 char *name; 290 { 291 ino_t ino; 292 293 ino = psearch(name); 294 if (ino == 0 || BIT(ino, dumpmap) == 0) 295 fprintf(stderr, "%s is not on tape\n", name); 296 return (ino); 297 } 298 299 /* 300 * Elicit a reply. 301 */ 302 reply(question) 303 char *question; 304 { 305 char c; 306 307 do { 308 fprintf(stderr, "%s? [yn] ", question); 309 (void) fflush(stderr); 310 c = getc(terminal); 311 while (c != '\n' && getc(terminal) != '\n') 312 if (feof(terminal)) 313 return (FAIL); 314 } while (c != 'y' && c != 'n'); 315 if (c == 'y') 316 return (GOOD); 317 return (FAIL); 318 } 319 320 /* 321 * handle unexpected inconsistencies 322 */ 323 /* VARARGS1 */ 324 panic(msg, d1, d2) 325 char *msg; 326 long d1, d2; 327 { 328 329 fprintf(stderr, msg, d1, d2); 330 if (yflag) 331 return; 332 if (reply("abort") == GOOD) { 333 if (reply("dump core") == GOOD) 334 abort(); 335 done(1); 336 } 337 } 338