| File: | src/sbin/restore/dirs.c |
| Warning: | line 545, column 26 The right operand of '-' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: dirs.c,v 1.42 2019/06/28 13:32:46 deraadt Exp $ */ | |||
| 2 | /* $NetBSD: dirs.c,v 1.26 1997/07/01 05:37:49 lukem Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1983, 1993 | |||
| 6 | * The Regents of the University of California. All rights reserved. | |||
| 7 | * (c) UNIX System Laboratories, Inc. | |||
| 8 | * All or some portions of this file are derived from material licensed | |||
| 9 | * to the University of California by American Telephone and Telegraph | |||
| 10 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |||
| 11 | * the permission of UNIX System Laboratories, Inc. | |||
| 12 | * | |||
| 13 | * Redistribution and use in source and binary forms, with or without | |||
| 14 | * modification, are permitted provided that the following conditions | |||
| 15 | * are met: | |||
| 16 | * 1. Redistributions of source code must retain the above copyright | |||
| 17 | * notice, this list of conditions and the following disclaimer. | |||
| 18 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 19 | * notice, this list of conditions and the following disclaimer in the | |||
| 20 | * documentation and/or other materials provided with the distribution. | |||
| 21 | * 3. Neither the name of the University nor the names of its contributors | |||
| 22 | * may be used to endorse or promote products derived from this software | |||
| 23 | * without specific prior written permission. | |||
| 24 | * | |||
| 25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 35 | * SUCH DAMAGE. | |||
| 36 | */ | |||
| 37 | ||||
| 38 | #include <sys/stat.h> | |||
| 39 | #include <sys/time.h> | |||
| 40 | ||||
| 41 | #include <ufs/ffs/fs.h> | |||
| 42 | #include <ufs/ufs/dinode.h> | |||
| 43 | #include <ufs/ufs/dir.h> | |||
| 44 | #include <protocols/dumprestore.h> | |||
| 45 | ||||
| 46 | #include <endian.h> | |||
| 47 | #include <err.h> | |||
| 48 | #include <errno(*__errno()).h> | |||
| 49 | #include <fcntl.h> | |||
| 50 | #include <paths.h> | |||
| 51 | #include <stdio.h> | |||
| 52 | #include <stdlib.h> | |||
| 53 | #include <string.h> | |||
| 54 | #include <unistd.h> | |||
| 55 | #include <limits.h> | |||
| 56 | ||||
| 57 | #include "restore.h" | |||
| 58 | #include "extern.h" | |||
| 59 | ||||
| 60 | /* | |||
| 61 | * Symbol table of directories read from tape. | |||
| 62 | */ | |||
| 63 | #define HASHSIZE1000 1000 | |||
| 64 | #define INOHASH(val)(val % 1000) (val % HASHSIZE1000) | |||
| 65 | struct inotab { | |||
| 66 | struct inotab *t_next; | |||
| 67 | ino_t t_ino; | |||
| 68 | int32_t t_seekpt; | |||
| 69 | int32_t t_size; | |||
| 70 | }; | |||
| 71 | static struct inotab *inotab[HASHSIZE1000]; | |||
| 72 | ||||
| 73 | /* | |||
| 74 | * Information retained about directories. | |||
| 75 | */ | |||
| 76 | struct modeinfo { | |||
| 77 | ino_t ino; | |||
| 78 | struct timespec ctimep[2]; | |||
| 79 | struct timespec mtimep[2]; | |||
| 80 | mode_t mode; | |||
| 81 | uid_t uid; | |||
| 82 | gid_t gid; | |||
| 83 | u_int flags; | |||
| 84 | }; | |||
| 85 | ||||
| 86 | /* | |||
| 87 | * Definitions for library routines operating on directories. | |||
| 88 | */ | |||
| 89 | #undef DIRBLKSIZ1024 | |||
| 90 | #define DIRBLKSIZ1024 1024 | |||
| 91 | struct rstdirdesc { | |||
| 92 | int dd_fd; | |||
| 93 | int32_t dd_loc; | |||
| 94 | int32_t dd_size; | |||
| 95 | char dd_buf[DIRBLKSIZ1024]; | |||
| 96 | }; | |||
| 97 | ||||
| 98 | /* | |||
| 99 | * Global variables for this file. | |||
| 100 | */ | |||
| 101 | static long seekpt; | |||
| 102 | static FILE *df, *mf; | |||
| 103 | static RST_DIR *dirp; | |||
| 104 | static char dirfile[PATH_MAX1024] = "#"; /* No file */ | |||
| 105 | static char modefile[PATH_MAX1024] = "#"; /* No file */ | |||
| 106 | static char dot[2] = "."; /* So it can be modified */ | |||
| 107 | ||||
| 108 | /* | |||
| 109 | * Format of old style directories. | |||
| 110 | */ | |||
| 111 | #define ODIRSIZ14 14 | |||
| 112 | struct odirect { | |||
| 113 | u_short d_ino; | |||
| 114 | char d_name[ODIRSIZ14]; | |||
| 115 | }; | |||
| 116 | ||||
| 117 | static struct inotab *allocinotab(FILE *, struct context *, long); | |||
| 118 | static void dcvt(struct odirect *, struct direct *); | |||
| 119 | static void flushent(void); | |||
| 120 | static struct inotab *inotablookup(ino_t); | |||
| 121 | static RST_DIR *opendirfile(const char *); | |||
| 122 | static void putdir(char *, size_t); | |||
| 123 | static void putent(struct direct *); | |||
| 124 | static void rst_seekdir(RST_DIR *, long, long); | |||
| 125 | static long rst_telldir(RST_DIR *); | |||
| 126 | static struct direct *searchdir(ino_t, char *); | |||
| 127 | ||||
| 128 | /* | |||
| 129 | * Extract directory contents, building up a directory structure | |||
| 130 | * on disk for extraction by name. | |||
| 131 | * If genmode is requested, save mode, owner, and times for all | |||
| 132 | * directories on the tape. | |||
| 133 | */ | |||
| 134 | void | |||
| 135 | extractdirs(int genmode) | |||
| 136 | { | |||
| 137 | int i; | |||
| 138 | struct inotab *itp; | |||
| 139 | struct direct nulldir; | |||
| 140 | int fd; | |||
| 141 | ||||
| 142 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "Extract directories from tape\n"); | |||
| 143 | (void)snprintf(dirfile, sizeof(dirfile), "%s/rstdir%lld", tmpdir, | |||
| 144 | (long long)dumpdate); | |||
| 145 | if (command != 'r' && command != 'R') { | |||
| 146 | strlcat(dirfile, "-XXXXXXXXXX", sizeof(dirfile)); | |||
| 147 | fd = mkstemp(dirfile); | |||
| 148 | } else | |||
| 149 | fd = open(dirfile, O_RDWR0x0002|O_CREAT0x0200|O_EXCL0x0800, 0666); | |||
| 150 | if (fd == -1 || (df = fdopen(fd, "w")) == NULL((void *)0)) { | |||
| 151 | int saved_errno = errno(*__errno()); | |||
| 152 | if (fd != -1) | |||
| 153 | close(fd); | |||
| 154 | errc(1, saved_errno, | |||
| 155 | "cannot create directory temporary %s", dirfile); | |||
| 156 | } | |||
| 157 | if (genmode != 0) { | |||
| 158 | (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld", | |||
| 159 | tmpdir, (long long)dumpdate); | |||
| 160 | if (command != 'r' && command != 'R') { | |||
| 161 | strlcat(modefile, "-XXXXXXXXXX", sizeof(modefile)); | |||
| 162 | fd = mkstemp(modefile); | |||
| 163 | } else | |||
| 164 | fd = open(modefile, O_RDWR0x0002|O_CREAT0x0200|O_EXCL0x0800, 0666); | |||
| 165 | if (fd == -1 || (mf = fdopen(fd, "w")) == NULL((void *)0)) { | |||
| 166 | int saved_errno = errno(*__errno()); | |||
| 167 | if (fd != -1) | |||
| 168 | close(fd); | |||
| 169 | errc(1, saved_errno, | |||
| 170 | "cannot create modefile %s", modefile); | |||
| 171 | } | |||
| 172 | } | |||
| 173 | nulldir.d_ino = 0; | |||
| 174 | nulldir.d_type = DT_DIR4; | |||
| 175 | nulldir.d_namlen = 1; | |||
| 176 | nulldir.d_name[0] = '/'; | |||
| 177 | nulldir.d_name[1] = '\0'; | |||
| 178 | nulldir.d_reclen = DIRSIZ(0, &nulldir)((0) ? ((sizeof(struct direct) - (255 +1)) + (((&nulldir) ->d_type+1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (((&nulldir)->d_namlen+1 + 3) &~ 3))); | |||
| 179 | for (;;) { | |||
| 180 | curfile.name = "<directory file - name unknown>"; | |||
| 181 | curfile.action = USING1; | |||
| 182 | if (curfile.mode == 0 || (curfile.mode & IFMT0170000) != IFDIR0040000) { | |||
| 183 | (void)fclose(df); | |||
| 184 | dirp = opendirfile(dirfile); | |||
| 185 | if (dirp == NULL((void *)0)) | |||
| 186 | warn("opendirfile"); | |||
| 187 | if (mf != NULL((void *)0)) | |||
| 188 | (void)fclose(mf); | |||
| 189 | i = dirlookup(dot); | |||
| 190 | if (i == 0) | |||
| 191 | panic("Root directory is not on tape\n"); | |||
| 192 | return; | |||
| 193 | } | |||
| 194 | itp = allocinotab(mf, &curfile, seekpt); | |||
| 195 | getfile(putdir, xtrnull); | |||
| 196 | putent(&nulldir); | |||
| 197 | flushent(); | |||
| 198 | itp->t_size = seekpt - itp->t_seekpt; | |||
| 199 | } | |||
| 200 | } | |||
| 201 | ||||
| 202 | /* | |||
| 203 | * skip over all the directories on the tape | |||
| 204 | */ | |||
| 205 | void | |||
| 206 | skipdirs(void) | |||
| 207 | { | |||
| 208 | ||||
| 209 | while (curfile.ino && (curfile.mode & IFMT0170000) == IFDIR0040000) { | |||
| 210 | skipfile(); | |||
| 211 | } | |||
| 212 | } | |||
| 213 | ||||
| 214 | /* | |||
| 215 | * Recursively find names and inumbers of all files in subtree | |||
| 216 | * pname and pass them off to be processed. | |||
| 217 | */ | |||
| 218 | void | |||
| 219 | treescan(char *pname, ino_t ino, long (*todo)(char *, ino_t, int)) | |||
| 220 | { | |||
| 221 | struct inotab *itp; | |||
| 222 | struct direct *dp; | |||
| 223 | size_t namelen; | |||
| 224 | long bpt; | |||
| 225 | char locname[PATH_MAX1024 + 1]; | |||
| 226 | ||||
| 227 | itp = inotablookup(ino); | |||
| 228 | if (itp == NULL((void *)0)) { | |||
| 229 | /* | |||
| 230 | * Pname is name of a simple file or an unchanged directory. | |||
| 231 | */ | |||
| 232 | (void)(*todo)(pname, ino, LEAF1); | |||
| 233 | return; | |||
| 234 | } | |||
| 235 | /* | |||
| 236 | * Pname is a dumped directory name. | |||
| 237 | */ | |||
| 238 | if ((*todo)(pname, ino, NODE2) == FAIL0) | |||
| 239 | return; | |||
| 240 | /* | |||
| 241 | * begin search through the directory | |||
| 242 | * skipping over "." and ".." | |||
| 243 | */ | |||
| 244 | namelen = strlcpy(locname, pname, sizeof(locname)); | |||
| 245 | if (namelen >= sizeof(locname) - 1) | |||
| 246 | namelen = sizeof(locname) - 2; | |||
| 247 | locname[namelen++] = '/'; | |||
| 248 | locname[namelen] = '\0'; | |||
| 249 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
| 250 | dp = rst_readdir(dirp); /* "." */ | |||
| 251 | if (dp != NULL((void *)0) && strcmp(dp->d_name, ".") == 0) | |||
| 252 | dp = rst_readdir(dirp); /* ".." */ | |||
| 253 | else | |||
| 254 | fprintf(stderr(&__sF[2]), "Warning: `.' missing from directory %s\n", | |||
| 255 | pname); | |||
| 256 | if (dp != NULL((void *)0) && strcmp(dp->d_name, "..") == 0) | |||
| 257 | dp = rst_readdir(dirp); /* first real entry */ | |||
| 258 | else | |||
| 259 | fprintf(stderr(&__sF[2]), "Warning: `..' missing from directory %s\n", | |||
| 260 | pname); | |||
| 261 | bpt = rst_telldir(dirp); | |||
| 262 | /* | |||
| 263 | * a zero inode signals end of directory | |||
| 264 | */ | |||
| 265 | while (dp != NULL((void *)0)) { | |||
| 266 | locname[namelen] = '\0'; | |||
| 267 | if (namelen + dp->d_namlen >= sizeof(locname)) { | |||
| 268 | fprintf(stderr(&__sF[2]), "%s%s: name exceeds %zd char\n", | |||
| 269 | locname, dp->d_name, sizeof(locname) - 1); | |||
| 270 | } else { | |||
| 271 | (void)strlcat(locname, dp->d_name, sizeof(locname)); | |||
| 272 | treescan(locname, dp->d_ino, todo); | |||
| 273 | rst_seekdir(dirp, bpt, itp->t_seekpt); | |||
| 274 | } | |||
| 275 | dp = rst_readdir(dirp); | |||
| 276 | bpt = rst_telldir(dirp); | |||
| 277 | } | |||
| 278 | } | |||
| 279 | ||||
| 280 | /* | |||
| 281 | * Lookup a pathname which is always assumed to start from the ROOTINO. | |||
| 282 | */ | |||
| 283 | struct direct * | |||
| 284 | pathsearch(const char *pathname) | |||
| 285 | { | |||
| 286 | ino_t ino; | |||
| 287 | struct direct *dp; | |||
| 288 | char *path, *name, buffer[PATH_MAX1024]; | |||
| 289 | ||||
| 290 | strlcpy(buffer, pathname, sizeof buffer); | |||
| 291 | path = buffer; | |||
| 292 | ino = ROOTINO((ufsino_t)2); | |||
| 293 | while (*path == '/') | |||
| 294 | path++; | |||
| 295 | dp = NULL((void *)0); | |||
| 296 | while ((name = strsep(&path, "/")) != NULL((void *)0) && *name != '\0') { | |||
| 297 | if ((dp = searchdir(ino, name)) == NULL((void *)0)) | |||
| 298 | return (NULL((void *)0)); | |||
| 299 | ino = dp->d_ino; | |||
| 300 | } | |||
| 301 | return (dp); | |||
| 302 | } | |||
| 303 | ||||
| 304 | /* | |||
| 305 | * Lookup the requested name in directory inum. | |||
| 306 | * Return its inode number if found, zero if it does not exist. | |||
| 307 | */ | |||
| 308 | static struct direct * | |||
| 309 | searchdir(ino_t inum, char *name) | |||
| 310 | { | |||
| 311 | struct direct *dp; | |||
| 312 | struct inotab *itp; | |||
| 313 | int len; | |||
| 314 | ||||
| 315 | itp = inotablookup(inum); | |||
| 316 | if (itp == NULL((void *)0)) | |||
| 317 | return (NULL((void *)0)); | |||
| 318 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
| 319 | len = strlen(name); | |||
| 320 | do { | |||
| 321 | dp = rst_readdir(dirp); | |||
| 322 | if (dp == NULL((void *)0)) | |||
| 323 | return (NULL((void *)0)); | |||
| 324 | } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); | |||
| 325 | return (dp); | |||
| 326 | } | |||
| 327 | ||||
| 328 | /* | |||
| 329 | * Put the directory entries in the directory file | |||
| 330 | */ | |||
| 331 | static void | |||
| 332 | putdir(char *buf, size_t size) | |||
| 333 | { | |||
| 334 | struct direct cvtbuf; | |||
| 335 | struct odirect *odp; | |||
| 336 | struct odirect *eodp; | |||
| 337 | struct direct *dp; | |||
| 338 | size_t loc, i; | |||
| 339 | ||||
| 340 | if (cvtflag) { | |||
| 341 | eodp = (struct odirect *)&buf[size]; | |||
| 342 | for (odp = (struct odirect *)buf; odp < eodp; odp++) | |||
| 343 | if (odp->d_ino != 0) { | |||
| 344 | dcvt(odp, &cvtbuf); | |||
| 345 | putent(&cvtbuf); | |||
| 346 | } | |||
| 347 | } else { | |||
| 348 | for (loc = 0; loc < size; ) { | |||
| 349 | dp = (struct direct *)(buf + loc); | |||
| 350 | if (Bcvt) { | |||
| 351 | dp->d_ino = swap32(dp->d_ino)(__uint32_t)(__builtin_constant_p(dp->d_ino) ? (__uint32_t )(((__uint32_t)(dp->d_ino) & 0xff) << 24 | ((__uint32_t )(dp->d_ino) & 0xff00) << 8 | ((__uint32_t)(dp-> d_ino) & 0xff0000) >> 8 | ((__uint32_t)(dp->d_ino ) & 0xff000000) >> 24) : __swap32md(dp->d_ino)); | |||
| 352 | dp->d_reclen = swap16(dp->d_reclen)(__uint16_t)(__builtin_constant_p(dp->d_reclen) ? (__uint16_t )(((__uint16_t)(dp->d_reclen) & 0xffU) << 8 | (( __uint16_t)(dp->d_reclen) & 0xff00U) >> 8) : __swap16md (dp->d_reclen)); | |||
| 353 | } | |||
| 354 | if (oldinofmt && dp->d_ino != 0) { | |||
| 355 | # if BYTE_ORDER1234 == BIG_ENDIAN4321 | |||
| 356 | if (Bcvt) | |||
| 357 | dp->d_namlen = dp->d_type; | |||
| 358 | # else | |||
| 359 | if (!Bcvt) | |||
| 360 | dp->d_namlen = dp->d_type; | |||
| 361 | # endif | |||
| 362 | dp->d_type = DT_UNKNOWN0; | |||
| 363 | } | |||
| 364 | i = DIRBLKSIZ1024 - (loc & (DIRBLKSIZ1024 - 1)); | |||
| 365 | if ((dp->d_reclen & 0x3) != 0 || | |||
| 366 | dp->d_reclen > i || | |||
| 367 | dp->d_reclen < DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3))) || | |||
| 368 | dp->d_namlen > NAME_MAX255) { | |||
| 369 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "Mangled directory: "); | |||
| 370 | if ((dp->d_reclen & 0x3) != 0) | |||
| 371 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), | |||
| 372 | "reclen not multiple of 4 "); | |||
| 373 | if (dp->d_reclen < DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3)))) | |||
| 374 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), | |||
| 375 | "reclen less than DIRSIZ (%u < %u) ", | |||
| 376 | (unsigned)dp->d_reclen, | |||
| 377 | (unsigned)DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3)))); | |||
| 378 | if (dp->d_namlen > NAME_MAX255) | |||
| 379 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), | |||
| 380 | "reclen name too big (%u > %u) ", | |||
| 381 | (unsigned)dp->d_namlen, NAME_MAX255); | |||
| 382 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "\n"); | |||
| 383 | loc += i; | |||
| 384 | continue; | |||
| 385 | } | |||
| 386 | loc += dp->d_reclen; | |||
| 387 | if (dp->d_ino != 0) { | |||
| 388 | putent(dp); | |||
| 389 | } | |||
| 390 | } | |||
| 391 | } | |||
| 392 | } | |||
| 393 | ||||
| 394 | /* | |||
| 395 | * These variables are "local" to the following two functions. | |||
| 396 | */ | |||
| 397 | char dirbuf[DIRBLKSIZ1024]; | |||
| 398 | long dirloc = 0; | |||
| 399 | long prev = 0; | |||
| 400 | ||||
| 401 | /* | |||
| 402 | * add a new directory entry to a file. | |||
| 403 | */ | |||
| 404 | static void | |||
| 405 | putent(struct direct *dp) | |||
| 406 | { | |||
| 407 | dp->d_reclen = DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3))); | |||
| 408 | if (dirloc + dp->d_reclen > DIRBLKSIZ1024) { | |||
| 409 | ((struct direct *)(dirbuf + prev))->d_reclen = | |||
| 410 | DIRBLKSIZ1024 - prev; | |||
| 411 | (void)fwrite(dirbuf, 1, DIRBLKSIZ1024, df); | |||
| 412 | dirloc = 0; | |||
| 413 | } | |||
| 414 | memcpy(dirbuf + dirloc, dp, dp->d_reclen); | |||
| 415 | prev = dirloc; | |||
| 416 | dirloc += dp->d_reclen; | |||
| 417 | } | |||
| 418 | ||||
| 419 | /* | |||
| 420 | * flush out a directory that is finished. | |||
| 421 | */ | |||
| 422 | static void | |||
| 423 | flushent(void) | |||
| 424 | { | |||
| 425 | ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ1024 - prev; | |||
| 426 | (void)fwrite(dirbuf, dirloc, 1, df); | |||
| 427 | seekpt = ftell(df); | |||
| 428 | dirloc = 0; | |||
| 429 | } | |||
| 430 | ||||
| 431 | static void | |||
| 432 | dcvt(struct odirect *odp, struct direct *ndp) | |||
| 433 | { | |||
| 434 | ||||
| 435 | memset(ndp, 0, sizeof *ndp); | |||
| 436 | if (Bcvt) | |||
| 437 | ndp->d_ino = swap16(odp->d_ino)(__uint16_t)(__builtin_constant_p(odp->d_ino) ? (__uint16_t )(((__uint16_t)(odp->d_ino) & 0xffU) << 8 | ((__uint16_t )(odp->d_ino) & 0xff00U) >> 8) : __swap16md(odp-> d_ino)); | |||
| 438 | else | |||
| 439 | ndp->d_ino = odp->d_ino; | |||
| 440 | ndp->d_type = DT_UNKNOWN0; | |||
| 441 | (void)strncpy(ndp->d_name, odp->d_name, ODIRSIZ14); | |||
| 442 | ndp->d_namlen = strlen(ndp->d_name); | |||
| 443 | ndp->d_reclen = DIRSIZ(0, ndp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((ndp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (ndp)->d_namlen+1 + 3) &~ 3))); | |||
| 444 | } | |||
| 445 | ||||
| 446 | /* | |||
| 447 | * Seek to an entry in a directory. | |||
| 448 | * Only values returned by rst_telldir should be passed to rst_seekdir. | |||
| 449 | * This routine handles many directories in a single file. | |||
| 450 | * It takes the base of the directory in the file, plus | |||
| 451 | * the desired seek offset into it. | |||
| 452 | */ | |||
| 453 | static void | |||
| 454 | rst_seekdir(RST_DIR *dirp, long loc, long base) | |||
| 455 | { | |||
| 456 | ||||
| 457 | if (loc == rst_telldir(dirp)) | |||
| 458 | return; | |||
| 459 | loc -= base; | |||
| 460 | if (loc < 0) | |||
| 461 | fprintf(stderr(&__sF[2]), "bad seek pointer to rst_seekdir %ld\n", loc); | |||
| 462 | (void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ1024 - 1)), SEEK_SET0); | |||
| 463 | dirp->dd_loc = loc & (DIRBLKSIZ1024 - 1); | |||
| 464 | if (dirp->dd_loc != 0) | |||
| 465 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ1024); | |||
| 466 | } | |||
| 467 | ||||
| 468 | /* | |||
| 469 | * get next entry in a directory. | |||
| 470 | */ | |||
| 471 | struct direct * | |||
| 472 | rst_readdir(RST_DIR *dirp) | |||
| 473 | { | |||
| 474 | struct direct *dp; | |||
| 475 | ||||
| 476 | for (;;) { | |||
| 477 | if (dirp->dd_loc == 0) { | |||
| 478 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, | |||
| 479 | DIRBLKSIZ1024); | |||
| 480 | if (dirp->dd_size <= 0) { | |||
| 481 | Dprintfif (dflag) fprintf(stderr(&__sF[2]), "error reading directory\n"); | |||
| 482 | return (NULL((void *)0)); | |||
| 483 | } | |||
| 484 | } | |||
| 485 | if (dirp->dd_loc >= dirp->dd_size) { | |||
| 486 | dirp->dd_loc = 0; | |||
| 487 | continue; | |||
| 488 | } | |||
| 489 | dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); | |||
| 490 | if (dp->d_reclen == 0 || | |||
| 491 | dp->d_reclen > DIRBLKSIZ1024 + 1 - dirp->dd_loc) { | |||
| 492 | Dprintfif (dflag) fprintf(stderr(&__sF[2]), "corrupted directory: bad reclen %d\n", | |||
| 493 | dp->d_reclen); | |||
| 494 | return (NULL((void *)0)); | |||
| 495 | } | |||
| 496 | dirp->dd_loc += dp->d_reclen; | |||
| 497 | if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) | |||
| 498 | return (NULL((void *)0)); | |||
| 499 | if (dp->d_ino >= maxino) { | |||
| 500 | Dprintfif (dflag) fprintf(stderr(&__sF[2]), "corrupted directory: bad inum %llu\n", | |||
| 501 | (unsigned long long)dp->d_ino); | |||
| 502 | continue; | |||
| 503 | } | |||
| 504 | return (dp); | |||
| 505 | } | |||
| 506 | } | |||
| 507 | ||||
| 508 | /* | |||
| 509 | * Simulate the opening of a directory | |||
| 510 | */ | |||
| 511 | RST_DIR * | |||
| 512 | rst_opendir(const char *name) | |||
| 513 | { | |||
| 514 | struct inotab *itp; | |||
| 515 | RST_DIR *dirp; | |||
| 516 | ino_t ino; | |||
| 517 | ||||
| 518 | if ((ino = dirlookup(name)) > 0 && | |||
| ||||
| 519 | (itp = inotablookup(ino)) != NULL((void *)0)) { | |||
| 520 | dirp = opendirfile(dirfile); | |||
| 521 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
| 522 | return (dirp); | |||
| 523 | } | |||
| 524 | return (NULL((void *)0)); | |||
| 525 | } | |||
| 526 | ||||
| 527 | /* | |||
| 528 | * In our case, there is nothing to do when closing a directory. | |||
| 529 | */ | |||
| 530 | void | |||
| 531 | rst_closedir(RST_DIR *dirp) | |||
| 532 | { | |||
| 533 | (void)close(dirp->dd_fd); | |||
| 534 | free(dirp); | |||
| 535 | return; | |||
| 536 | } | |||
| 537 | ||||
| 538 | /* | |||
| 539 | * Simulate finding the current offset in the directory. | |||
| 540 | */ | |||
| 541 | static long | |||
| 542 | rst_telldir(RST_DIR *dirp) | |||
| 543 | { | |||
| 544 | return ((long)lseek(dirp->dd_fd, | |||
| 545 | (off_t)0, SEEK_CUR1) - dirp->dd_size + dirp->dd_loc); | |||
| ||||
| 546 | } | |||
| 547 | ||||
| 548 | /* | |||
| 549 | * Open a directory file. | |||
| 550 | */ | |||
| 551 | static RST_DIR * | |||
| 552 | opendirfile(const char *name) | |||
| 553 | { | |||
| 554 | RST_DIR *dirp; | |||
| 555 | int fd; | |||
| 556 | ||||
| 557 | if ((fd = open(name, O_RDONLY0x0000)) == -1) | |||
| 558 | return (NULL((void *)0)); | |||
| 559 | if ((dirp = malloc(sizeof(RST_DIR))) == NULL((void *)0)) { | |||
| 560 | (void)close(fd); | |||
| 561 | return (NULL((void *)0)); | |||
| 562 | } | |||
| 563 | dirp->dd_fd = fd; | |||
| 564 | dirp->dd_loc = 0; | |||
| 565 | return (dirp); | |||
| 566 | } | |||
| 567 | ||||
| 568 | /* | |||
| 569 | * Set the mode, owner, and times for all new or changed directories | |||
| 570 | */ | |||
| 571 | void | |||
| 572 | setdirmodes(int flags) | |||
| 573 | { | |||
| 574 | FILE *mf; | |||
| 575 | struct modeinfo node; | |||
| 576 | struct entry *ep; | |||
| 577 | char *cp; | |||
| 578 | ||||
| 579 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "Set directory mode, owner, and times.\n"); | |||
| 580 | if (command == 'r' || command == 'R') | |||
| 581 | (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld", | |||
| 582 | tmpdir, (long long)dumpdate); | |||
| 583 | if (modefile[0] == '#') { | |||
| 584 | panic("modefile not defined\n"); | |||
| 585 | fputs("directory mode, owner, and times not set\n", stderr(&__sF[2])); | |||
| 586 | return; | |||
| 587 | } | |||
| 588 | mf = fopen(modefile, "r"); | |||
| 589 | if (mf == NULL((void *)0)) { | |||
| 590 | warn("fopen"); | |||
| 591 | fprintf(stderr(&__sF[2]), "cannot open mode file %s\n", modefile); | |||
| 592 | fprintf(stderr(&__sF[2]), "directory mode, owner, and times not set\n"); | |||
| 593 | return; | |||
| 594 | } | |||
| 595 | clearerr(mf)(!__isthreaded ? ((void)((mf)->_flags &= ~(0x0040|0x0020 ))) : (clearerr)(mf)); | |||
| 596 | for (;;) { | |||
| 597 | (void)fread((char *)&node, 1, sizeof(struct modeinfo), mf); | |||
| 598 | if (feof(mf)(!__isthreaded ? (((mf)->_flags & 0x0020) != 0) : (feof )(mf))) | |||
| 599 | break; | |||
| 600 | ep = lookupino(node.ino); | |||
| 601 | if (command == 'i' || command == 'x') { | |||
| 602 | if (ep == NULL((void *)0)) | |||
| 603 | continue; | |||
| 604 | if ((flags & FORCE0x0001) == 0 && ep->e_flags & EXISTED0x0040) { | |||
| 605 | ep->e_flags &= ~NEW0x0002; | |||
| 606 | continue; | |||
| 607 | } | |||
| 608 | if (node.ino == ROOTINO((ufsino_t)2) && | |||
| 609 | reply("set owner/mode for '.'") == FAIL0) | |||
| 610 | continue; | |||
| 611 | } | |||
| 612 | if (ep == NULL((void *)0)) { | |||
| 613 | panic("cannot find directory inode %llu\n", | |||
| 614 | (unsigned long long)node.ino); | |||
| 615 | } else { | |||
| 616 | if (!Nflag) { | |||
| 617 | cp = myname(ep); | |||
| 618 | (void)chown(cp, node.uid, node.gid); | |||
| 619 | (void)chmod(cp, node.mode); | |||
| 620 | (void)chflags(cp, node.flags); | |||
| 621 | (void)utimensat(AT_FDCWD-100, cp, node.ctimep, 0); | |||
| 622 | (void)utimensat(AT_FDCWD-100, cp, node.mtimep, 0); | |||
| 623 | } | |||
| 624 | ep->e_flags &= ~NEW0x0002; | |||
| 625 | } | |||
| 626 | } | |||
| 627 | if (ferror(mf)(!__isthreaded ? (((mf)->_flags & 0x0040) != 0) : (ferror )(mf))) | |||
| 628 | panic("error setting directory modes\n"); | |||
| 629 | (void)fclose(mf); | |||
| 630 | } | |||
| 631 | ||||
| 632 | /* | |||
| 633 | * Generate a literal copy of a directory. | |||
| 634 | */ | |||
| 635 | int | |||
| 636 | genliteraldir(char *name, ino_t ino) | |||
| 637 | { | |||
| 638 | struct inotab *itp; | |||
| 639 | int ofile, dp, i, size; | |||
| 640 | char buf[BUFSIZ1024]; | |||
| 641 | ||||
| 642 | itp = inotablookup(ino); | |||
| 643 | if (itp == NULL((void *)0)) | |||
| 644 | panic("Cannot find directory inode %llu named %s\n", | |||
| 645 | (unsigned long long)ino, name); | |||
| 646 | if ((ofile = open(name, O_WRONLY0x0001 | O_CREAT0x0200 | O_TRUNC0x0400, 0666)) == -1) { | |||
| 647 | warn("%s: cannot create file", name); | |||
| 648 | return (FAIL0); | |||
| 649 | } | |||
| 650 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
| 651 | dp = dup(dirp->dd_fd); | |||
| 652 | for (i = itp->t_size; i > 0; i -= BUFSIZ1024) { | |||
| 653 | size = i < BUFSIZ1024 ? i : BUFSIZ1024; | |||
| 654 | if (read(dp, buf, size) == -1) | |||
| 655 | err(1, "read error extracting inode %llu, name %s", | |||
| 656 | (unsigned long long)curfile.ino, curfile.name); | |||
| 657 | xtrfile(buf, size); | |||
| 658 | } | |||
| 659 | (void)close(dp); | |||
| 660 | (void)close(ofile); | |||
| 661 | return (GOOD1); | |||
| 662 | } | |||
| 663 | ||||
| 664 | /* | |||
| 665 | * Determine the type of an inode | |||
| 666 | */ | |||
| 667 | int | |||
| 668 | inodetype(ino_t ino) | |||
| 669 | { | |||
| 670 | struct inotab *itp; | |||
| 671 | ||||
| 672 | itp = inotablookup(ino); | |||
| 673 | if (itp == NULL((void *)0)) | |||
| 674 | return (LEAF1); | |||
| 675 | return (NODE2); | |||
| 676 | } | |||
| 677 | ||||
| 678 | /* | |||
| 679 | * Allocate and initialize a directory inode entry. | |||
| 680 | * If requested, save its pertinent mode, owner, and time info. | |||
| 681 | */ | |||
| 682 | static struct inotab * | |||
| 683 | allocinotab(FILE *mf, struct context *ctxp, long seekpt) | |||
| 684 | { | |||
| 685 | struct inotab *itp; | |||
| 686 | struct modeinfo node; | |||
| 687 | ||||
| 688 | itp = calloc(1, sizeof(struct inotab)); | |||
| 689 | if (itp == NULL((void *)0)) | |||
| 690 | panic("no memory directory table\n"); | |||
| 691 | itp->t_next = inotab[INOHASH(ctxp->ino)(ctxp->ino % 1000)]; | |||
| 692 | inotab[INOHASH(ctxp->ino)(ctxp->ino % 1000)] = itp; | |||
| 693 | itp->t_ino = ctxp->ino; | |||
| 694 | itp->t_seekpt = seekpt; | |||
| 695 | if (mf == NULL((void *)0)) | |||
| 696 | return (itp); | |||
| 697 | node.ino = ctxp->ino; | |||
| 698 | node.mtimep[0].tv_sec = ctxp->atime_sec; | |||
| 699 | node.mtimep[0].tv_nsec = ctxp->atime_nsec; | |||
| 700 | node.mtimep[1].tv_sec = ctxp->mtime_sec; | |||
| 701 | node.mtimep[1].tv_nsec = ctxp->mtime_nsec; | |||
| 702 | node.ctimep[0].tv_sec = ctxp->atime_sec; | |||
| 703 | node.ctimep[0].tv_nsec = ctxp->atime_nsec; | |||
| 704 | node.ctimep[1].tv_sec = ctxp->birthtime_sec; | |||
| 705 | node.ctimep[1].tv_nsec = ctxp->birthtime_nsec; | |||
| 706 | node.mode = ctxp->mode; | |||
| 707 | node.flags = ctxp->file_flags; | |||
| 708 | node.uid = ctxp->uid; | |||
| 709 | node.gid = ctxp->gid; | |||
| 710 | (void)fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); | |||
| 711 | return (itp); | |||
| 712 | } | |||
| 713 | ||||
| 714 | /* | |||
| 715 | * Look up an inode in the table of directories | |||
| 716 | */ | |||
| 717 | static struct inotab * | |||
| 718 | inotablookup(ino_t ino) | |||
| 719 | { | |||
| 720 | struct inotab *itp; | |||
| 721 | ||||
| 722 | for (itp = inotab[INOHASH(ino)(ino % 1000)]; itp != NULL((void *)0); itp = itp->t_next) | |||
| 723 | if (itp->t_ino == ino) | |||
| 724 | return (itp); | |||
| 725 | return (NULL((void *)0)); | |||
| 726 | } | |||
| 727 | ||||
| 728 | /* | |||
| 729 | * Clean up and exit | |||
| 730 | */ | |||
| 731 | void | |||
| 732 | cleanup(void) | |||
| 733 | { | |||
| 734 | ||||
| 735 | closemt(); | |||
| 736 | if (modefile[0] != '#') | |||
| 737 | (void)unlink(modefile); | |||
| 738 | if (dirfile[0] != '#') | |||
| 739 | (void)unlink(dirfile); | |||
| 740 | } |