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