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