1 1.1 tsutsui /* 2 1.1 tsutsui * File multi.c - scan existing iso9660 image and merge into 3 1.1 tsutsui * iso9660 filesystem. Used for multisession support. 4 1.1 tsutsui * 5 1.1 tsutsui * Written by Eric Youngdale (1996). 6 1.1 tsutsui * 7 1.1 tsutsui * This program is free software; you can redistribute it and/or modify 8 1.1 tsutsui * it under the terms of the GNU General Public License as published by 9 1.1 tsutsui * the Free Software Foundation; either version 2, or (at your option) 10 1.1 tsutsui * any later version. 11 1.1 tsutsui * 12 1.1 tsutsui * This program is distributed in the hope that it will be useful, 13 1.1 tsutsui * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 tsutsui * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 tsutsui * GNU General Public License for more details. 16 1.1 tsutsui * 17 1.1 tsutsui * You should have received a copy of the GNU General Public License 18 1.1 tsutsui * along with this program; if not, write to the Free Software 19 1.1 tsutsui * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 1.1 tsutsui */ 21 1.1 tsutsui 22 1.1 tsutsui #include <stdlib.h> 23 1.1 tsutsui #include <string.h> 24 1.1 tsutsui #include <time.h> 25 1.1 tsutsui #include <errno.h> 26 1.1 tsutsui #include <sys/types.h> 27 1.1 tsutsui #include <sys/stat.h> 28 1.1 tsutsui 29 1.1 tsutsui #include "config.h" 30 1.1 tsutsui 31 1.1 tsutsui #ifndef VMS 32 1.1 tsutsui 33 1.1 tsutsui #ifdef HAVE_UNISTD_H 34 1.1 tsutsui #include <unistd.h> 35 1.1 tsutsui #endif 36 1.1 tsutsui 37 1.1 tsutsui #else 38 1.1 tsutsui #include <sys/file.h> 39 1.1 tsutsui #include <vms/fabdef.h> 40 1.1 tsutsui #include "vms.h" 41 1.1 tsutsui extern char * strdup(const char *); 42 1.1 tsutsui #endif 43 1.1 tsutsui 44 1.1 tsutsui #include "mkisofs.h" 45 1.1 tsutsui #include "iso9660.h" 46 1.1 tsutsui 47 1.1 tsutsui #define TF_CREATE 1 48 1.1 tsutsui #define TF_MODIFY 2 49 1.1 tsutsui #define TF_ACCESS 4 50 1.1 tsutsui #define TF_ATTRIBUTES 8 51 1.1 tsutsui 52 1.1 tsutsui static int isonum_711 __PR((unsigned char * p)); 53 1.1 tsutsui static int isonum_721 __PR((unsigned char * p)); 54 1.1 tsutsui static int isonum_723 __PR((unsigned char * p)); 55 1.1 tsutsui static int isonum_731 __PR((unsigned char * p)); 56 1.1 tsutsui 57 1.1 tsutsui static int DECL(merge_old_directory_into_tree, (struct directory_entry *, 58 1.1 tsutsui struct directory *)); 59 1.1 tsutsui 60 1.1 tsutsui #ifdef __STDC__ 61 1.1 tsutsui static int 62 1.1 tsutsui isonum_711 (unsigned char * p) 63 1.1 tsutsui #else 64 1.1 tsutsui static int 65 1.1 tsutsui isonum_711 (p) 66 1.1 tsutsui unsigned char * p; 67 1.1 tsutsui #endif 68 1.1 tsutsui { 69 1.1 tsutsui return (*p & 0xff); 70 1.1 tsutsui } 71 1.1 tsutsui 72 1.1 tsutsui #ifdef __STDC__ 73 1.1 tsutsui static int 74 1.1 tsutsui isonum_721 (unsigned char * p) 75 1.1 tsutsui #else 76 1.1 tsutsui static int 77 1.1 tsutsui isonum_721 (p) 78 1.1 tsutsui unsigned char * p; 79 1.1 tsutsui #endif 80 1.1 tsutsui { 81 1.1 tsutsui return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); 82 1.1 tsutsui } 83 1.1 tsutsui 84 1.1 tsutsui #ifdef __STDC__ 85 1.1 tsutsui static int 86 1.1 tsutsui isonum_723 (unsigned char * p) 87 1.1 tsutsui #else 88 1.1 tsutsui static int 89 1.1 tsutsui isonum_723 (p) 90 1.1 tsutsui unsigned char * p; 91 1.1 tsutsui #endif 92 1.1 tsutsui { 93 1.1 tsutsui #if 0 94 1.1 tsutsui if (p[0] != p[3] || p[1] != p[2]) { 95 1.1 tsutsui fprintf (stderr, "invalid format 7.2.3 number\n"); 96 1.1 tsutsui exit (1); 97 1.1 tsutsui } 98 1.1 tsutsui #endif 99 1.1 tsutsui return (isonum_721 (p)); 100 1.1 tsutsui } 101 1.1 tsutsui 102 1.1 tsutsui #ifdef __STDC__ 103 1.1 tsutsui static int 104 1.1 tsutsui isonum_731 (unsigned char * p) 105 1.1 tsutsui #else 106 1.1 tsutsui static int 107 1.1 tsutsui isonum_731 (p) 108 1.1 tsutsui unsigned char * p; 109 1.1 tsutsui #endif 110 1.1 tsutsui { 111 1.1 tsutsui return ((p[0] & 0xff) 112 1.1 tsutsui | ((p[1] & 0xff) << 8) 113 1.1 tsutsui | ((p[2] & 0xff) << 16) 114 1.1 tsutsui | ((p[3] & 0xff) << 24)); 115 1.1 tsutsui } 116 1.1 tsutsui 117 1.1 tsutsui #ifdef __STDC__ 118 1.1 tsutsui int 119 1.1 tsutsui isonum_733 (unsigned char * p) 120 1.1 tsutsui #else 121 1.1 tsutsui int 122 1.1 tsutsui isonum_733 (p) 123 1.1 tsutsui unsigned char * p; 124 1.1 tsutsui #endif 125 1.1 tsutsui { 126 1.1 tsutsui return (isonum_731 (p)); 127 1.1 tsutsui } 128 1.1 tsutsui 129 1.1 tsutsui FILE * in_image = NULL; 130 1.1 tsutsui 131 1.1 tsutsui #ifndef USE_SCG 132 1.1 tsutsui /* 133 1.1 tsutsui * Don't define readsecs if mkisofs is linked with 134 1.1 tsutsui * the SCSI library. 135 1.1 tsutsui * readsecs() will be implemented as SCSI command in this case. 136 1.1 tsutsui * 137 1.1 tsutsui * Use global var in_image directly in readsecs() 138 1.1 tsutsui * the SCSI equivalent will not use a FILE* for I/O. 139 1.1 tsutsui * 140 1.1 tsutsui * The main point of this pointless abstraction is that Solaris won't let 141 1.1 tsutsui * you read 2K sectors from the cdrom driver. The fact that 99.9% of the 142 1.1 tsutsui * discs out there have a 2K sectorsize doesn't seem to matter that much. 143 1.1 tsutsui * Anyways, this allows the use of a scsi-generics type of interface on 144 1.1 tsutsui * Solaris. 145 1.1 tsutsui */ 146 1.1 tsutsui #ifdef __STDC__ 147 1.1 tsutsui static int 148 1.1 tsutsui readsecs(int startsecno, void *buffer, int sectorcount) 149 1.1 tsutsui #else 150 1.1 tsutsui static int 151 1.1 tsutsui readsecs(startsecno, buffer, sectorcount) 152 1.1 tsutsui int startsecno; 153 1.1 tsutsui void *buffer; 154 1.1 tsutsui int sectorcount; 155 1.1 tsutsui #endif 156 1.1 tsutsui { 157 1.1 tsutsui int f = fileno(in_image); 158 1.1 tsutsui 159 1.1 tsutsui if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) { 160 1.1 tsutsui fprintf(stderr," Seek error on old image\n"); 161 1.1 tsutsui exit(10); 162 1.1 tsutsui } 163 1.1 tsutsui return (read(f, buffer, sectorcount * SECTOR_SIZE)); 164 1.1 tsutsui } 165 1.1 tsutsui #endif 166 1.1 tsutsui 167 1.1 tsutsui /* 168 1.1 tsutsui * Parse the RR attributes so we can find the file name. 169 1.1 tsutsui */ 170 1.1 tsutsui static int 171 1.1 tsutsui FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt) 172 1.1 tsutsui { 173 1.1 tsutsui int cont_extent, cont_offset, cont_size; 174 1.1 tsutsui char name_buf[256]; 175 1.1 tsutsui 176 1.1 tsutsui cont_extent = cont_offset = cont_size = 0; 177 1.1 tsutsui 178 1.1 tsutsui while(len >= 4){ 179 1.1 tsutsui if(pnt[3] != 1) { 180 1.1 tsutsui fprintf(stderr,"**BAD RRVERSION"); 181 1.1 tsutsui return -1; 182 1.1 tsutsui }; 183 1.1 tsutsui if(strncmp((char *) pnt, "NM", 2) == 0) { 184 1.1 tsutsui strncpy(name_buf, (char *) pnt+5, pnt[2] - 5); 185 1.1 tsutsui name_buf[pnt[2] - 5] = 0; 186 1.1 tsutsui dpnt->name = strdup(name_buf); 187 1.1 tsutsui dpnt->got_rr_name = 1; 188 1.1 tsutsui return 0; 189 1.1 tsutsui } 190 1.1 tsutsui 191 1.1 tsutsui if(strncmp((char *) pnt, "CE", 2) == 0) { 192 1.1 tsutsui cont_extent = isonum_733(pnt+4); 193 1.1 tsutsui cont_offset = isonum_733(pnt+12); 194 1.1 tsutsui cont_size = isonum_733(pnt+20); 195 1.1 tsutsui }; 196 1.1 tsutsui 197 1.1 tsutsui len -= pnt[2]; 198 1.1 tsutsui pnt += pnt[2]; 199 1.1 tsutsui if(len <= 3 && cont_extent) { 200 1.1 tsutsui unsigned char sector[SECTOR_SIZE]; 201 1.1 tsutsui readsecs(cont_extent, sector, 1); 202 1.1 tsutsui parse_rr(§or[cont_offset], cont_size, dpnt); 203 1.1 tsutsui }; 204 1.1 tsutsui }; 205 1.1 tsutsui 206 1.1 tsutsui /* Fall back to the iso name if no RR name found */ 207 1.1 tsutsui if (dpnt->name == NULL) { 208 1.1 tsutsui char *cp; 209 1.1 tsutsui 210 1.1 tsutsui strcpy(name_buf, dpnt->isorec.name); 211 1.1 tsutsui cp = strchr(name_buf, ';'); 212 1.1 tsutsui if (cp != NULL) { 213 1.1 tsutsui *cp = '\0'; 214 1.1 tsutsui } 215 1.1 tsutsui 216 1.1 tsutsui dpnt->name = strdup(name_buf); 217 1.1 tsutsui } 218 1.1 tsutsui 219 1.1 tsutsui return 0; 220 1.1 tsutsui } /* parse_rr */ 221 1.1 tsutsui 222 1.1 tsutsui 223 1.1 tsutsui static int 224 1.1 tsutsui FDECL4(check_rr_dates, struct directory_entry *, dpnt, 225 1.1 tsutsui struct directory_entry *, current, 226 1.1 tsutsui struct stat *, statbuf, 227 1.1 tsutsui struct stat *,lstatbuf) 228 1.1 tsutsui { 229 1.1 tsutsui int cont_extent, cont_offset, cont_size; 230 1.1 tsutsui int offset; 231 1.1 tsutsui unsigned char * pnt; 232 1.1 tsutsui int len; 233 1.1 tsutsui int same_file; 234 1.1 tsutsui int same_file_type; 235 1.1 tsutsui mode_t mode; 236 1.1 tsutsui char time_buf[7]; 237 1.1 tsutsui 238 1.1 tsutsui 239 1.1 tsutsui cont_extent = cont_offset = cont_size = 0; 240 1.1 tsutsui same_file = 1; 241 1.1 tsutsui same_file_type = 1; 242 1.1 tsutsui 243 1.1 tsutsui pnt = dpnt->rr_attributes; 244 1.1 tsutsui len = dpnt->rr_attr_size; 245 1.1 tsutsui /* 246 1.1 tsutsui * We basically need to parse the rr attributes again, and 247 1.1 tsutsui * dig out the dates and file types. 248 1.1 tsutsui */ 249 1.1 tsutsui while(len >= 4){ 250 1.1 tsutsui if(pnt[3] != 1) { 251 1.1 tsutsui fprintf(stderr,"**BAD RRVERSION"); 252 1.1 tsutsui return -1; 253 1.1 tsutsui }; 254 1.1 tsutsui 255 1.1 tsutsui /* 256 1.1 tsutsui * If we have POSIX file modes, make sure that the file type 257 1.1 tsutsui * is the same. If it isn't, then we must always 258 1.1 tsutsui * write the new file. 259 1.1 tsutsui */ 260 1.1 tsutsui if(strncmp((char *) pnt, "PX", 2) == 0) { 261 1.1 tsutsui mode = isonum_733(pnt + 4); 262 1.1 tsutsui if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) ) 263 1.1 tsutsui { 264 1.1 tsutsui same_file_type = 0; 265 1.1 tsutsui same_file = 0; 266 1.1 tsutsui } 267 1.1 tsutsui } 268 1.1 tsutsui 269 1.1 tsutsui if(strncmp((char *) pnt, "TF", 2) == 0) { 270 1.1 tsutsui offset = 5; 271 1.1 tsutsui if( pnt[4] & TF_CREATE ) 272 1.1 tsutsui { 273 1.1 tsutsui iso9660_date((char *) time_buf, lstatbuf->st_ctime); 274 1.1 tsutsui if(memcmp(time_buf, pnt+offset, 7) == 0) 275 1.1 tsutsui same_file = 0; 276 1.1 tsutsui offset += 7; 277 1.1 tsutsui } 278 1.1 tsutsui if( pnt[4] & TF_MODIFY ) 279 1.1 tsutsui { 280 1.1 tsutsui iso9660_date((char *) time_buf, lstatbuf->st_mtime); 281 1.1 tsutsui if(memcmp(time_buf, pnt+offset, 7) == 0) 282 1.1 tsutsui same_file = 0; 283 1.1 tsutsui offset += 7; 284 1.1 tsutsui } 285 1.1 tsutsui } 286 1.1 tsutsui 287 1.1 tsutsui if(strncmp((char *) pnt, "CE", 2) == 0) { 288 1.1 tsutsui cont_extent = isonum_733(pnt+4); 289 1.1 tsutsui cont_offset = isonum_733(pnt+12); 290 1.1 tsutsui cont_size = isonum_733(pnt+20); 291 1.1 tsutsui }; 292 1.1 tsutsui 293 1.1 tsutsui len -= pnt[2]; 294 1.1 tsutsui pnt += pnt[2]; 295 1.1 tsutsui if(len <= 3 && cont_extent) { 296 1.1 tsutsui unsigned char sector[SECTOR_SIZE]; 297 1.1 tsutsui 298 1.1 tsutsui readsecs(cont_extent, sector, 1); 299 1.1 tsutsui parse_rr(§or[cont_offset], cont_size, dpnt); 300 1.1 tsutsui }; 301 1.1 tsutsui }; 302 1.1 tsutsui 303 1.1 tsutsui /* 304 1.1 tsutsui * If we have the same fundamental file type, then it is clearly 305 1.1 tsutsui * safe to reuse the TRANS.TBL entry. 306 1.1 tsutsui */ 307 1.1 tsutsui if( same_file_type ) 308 1.1 tsutsui { 309 1.1 tsutsui current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; 310 1.1 tsutsui } 311 1.1 tsutsui 312 1.1 tsutsui return same_file; 313 1.1 tsutsui } 314 1.1 tsutsui 315 1.1 tsutsui struct directory_entry ** 316 1.1 tsutsui FDECL2(read_merging_directory, struct iso_directory_record *, mrootp, 317 1.1 tsutsui int *, nent) 318 1.1 tsutsui { 319 1.1 tsutsui unsigned char * cpnt; 320 1.1 tsutsui unsigned char * cpnt1; 321 1.1 tsutsui char * dirbuff; 322 1.1 tsutsui int i; 323 1.1 tsutsui struct iso_directory_record * idr; 324 1.1 tsutsui int len; 325 1.1 tsutsui struct directory_entry **pnt; 326 1.1 tsutsui int rlen; 327 1.1 tsutsui struct directory_entry **rtn; 328 1.1 tsutsui int seen_rockridge; 329 1.1 tsutsui unsigned char * tt_buf; 330 1.1 tsutsui int tt_extent; 331 1.1 tsutsui int tt_size; 332 1.1 tsutsui 333 1.1 tsutsui static int warning_given = 0; 334 1.1 tsutsui 335 1.1 tsutsui /* 336 1.1 tsutsui * First, allocate a buffer large enough to read in the entire 337 1.1 tsutsui * directory. 338 1.1 tsutsui */ 339 1.1 tsutsui dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size)); 340 1.1 tsutsui 341 1.1 tsutsui readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff, 342 1.1 tsutsui isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE); 343 1.1 tsutsui 344 1.1 tsutsui /* 345 1.1 tsutsui * Next look over the directory, and count up how many entries we 346 1.1 tsutsui * have. 347 1.1 tsutsui */ 348 1.1 tsutsui len = isonum_733((unsigned char *)mrootp->size); 349 1.1 tsutsui i = 0; 350 1.1 tsutsui *nent = 0; 351 1.1 tsutsui while(i < len ) 352 1.1 tsutsui { 353 1.1 tsutsui idr = (struct iso_directory_record *) &dirbuff[i]; 354 1.1 tsutsui if(idr->length[0] == 0) 355 1.1 tsutsui { 356 1.1 tsutsui i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); 357 1.1 tsutsui continue; 358 1.1 tsutsui } 359 1.1 tsutsui (*nent)++; 360 1.1 tsutsui i += idr->length[0]; 361 1.1 tsutsui } 362 1.1 tsutsui 363 1.1 tsutsui /* 364 1.1 tsutsui * Now allocate the buffer which will hold the array we are 365 1.1 tsutsui * about to return. 366 1.1 tsutsui */ 367 1.1 tsutsui rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); 368 1.1 tsutsui 369 1.1 tsutsui /* 370 1.1 tsutsui * Finally, scan the directory one last time, and pick out the 371 1.1 tsutsui * relevant bits of information, and store it in the relevant 372 1.1 tsutsui * bits of the structure. 373 1.1 tsutsui */ 374 1.1 tsutsui i = 0; 375 1.1 tsutsui pnt = rtn; 376 1.1 tsutsui tt_extent = 0; 377 1.1 tsutsui seen_rockridge = 0; 378 1.1 tsutsui tt_size = 0; 379 1.1 tsutsui while(i < len ) 380 1.1 tsutsui { 381 1.1 tsutsui idr = (struct iso_directory_record *) &dirbuff[i]; 382 1.1 tsutsui if(idr->length[0] == 0) 383 1.1 tsutsui { 384 1.1 tsutsui i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); 385 1.1 tsutsui continue; 386 1.1 tsutsui } 387 1.1 tsutsui *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn)); 388 1.1 tsutsui (*pnt)->next = NULL; 389 1.1 tsutsui (*pnt)->isorec = *idr; 390 1.1 tsutsui (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent); 391 1.1 tsutsui (*pnt)->size = isonum_733((unsigned char *)idr->size); 392 1.1 tsutsui (*pnt)->priority = 0; 393 1.1 tsutsui (*pnt)->name = NULL; 394 1.1 tsutsui (*pnt)->got_rr_name = 0; 395 1.1 tsutsui (*pnt)->table = NULL; 396 1.1 tsutsui (*pnt)->whole_name = NULL; 397 1.1 tsutsui (*pnt)->filedir = NULL; 398 1.1 tsutsui (*pnt)->parent_rec = NULL; 399 1.1 tsutsui /* 400 1.1 tsutsui * Set this information so that we correctly cache previous 401 1.1 tsutsui * session bits of information. 402 1.1 tsutsui */ 403 1.1 tsutsui (*pnt)->inode = (*pnt)->starting_block; 404 1.1 tsutsui (*pnt)->dev = PREV_SESS_DEV; 405 1.1 tsutsui (*pnt)->rr_attributes = NULL; 406 1.1 tsutsui (*pnt)->rr_attr_size = 0; 407 1.1 tsutsui (*pnt)->total_rr_attr_size = 0; 408 1.1 tsutsui (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY; 409 1.1 tsutsui 410 1.1 tsutsui /* 411 1.1 tsutsui * Check for and parse any RR attributes for the file. 412 1.1 tsutsui * All we are really looking for here is the original name 413 1.1 tsutsui * of the file. 414 1.1 tsutsui */ 415 1.1 tsutsui rlen = idr->length[0] & 0xff; 416 1.1 tsutsui cpnt = (unsigned char *) idr; 417 1.1 tsutsui 418 1.1 tsutsui rlen -= sizeof(struct iso_directory_record); 419 1.1 tsutsui cpnt += sizeof(struct iso_directory_record); 420 1.1 tsutsui 421 1.1 tsutsui rlen += sizeof(idr->name); 422 1.1 tsutsui cpnt -= sizeof(idr->name); 423 1.1 tsutsui 424 1.1 tsutsui rlen -= idr->name_len[0]; 425 1.1 tsutsui cpnt += idr->name_len[0]; 426 1.1 tsutsui 427 1.1 tsutsui if((idr->name_len[0] & 1) == 0){ 428 1.1 tsutsui cpnt++; 429 1.1 tsutsui rlen--; 430 1.1 tsutsui }; 431 1.1 tsutsui 432 1.1 tsutsui if( rlen != 0 ) 433 1.1 tsutsui { 434 1.1 tsutsui (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen; 435 1.1 tsutsui (*pnt)->rr_attributes = e_malloc(rlen); 436 1.1 tsutsui memcpy((*pnt)->rr_attributes, cpnt, rlen); 437 1.1 tsutsui seen_rockridge = 1; 438 1.1 tsutsui } 439 1.1 tsutsui 440 1.1 tsutsui /* 441 1.1 tsutsui * Now zero out the remainder of the name field. 442 1.1 tsutsui */ 443 1.1 tsutsui cpnt = (unsigned char *) &(*pnt)->isorec.name; 444 1.1 tsutsui cpnt += idr->name_len[0]; 445 1.1 tsutsui memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]); 446 1.1 tsutsui 447 1.1 tsutsui parse_rr((*pnt)->rr_attributes, rlen, *pnt); 448 1.1 tsutsui 449 1.1 tsutsui if( ((*pnt)->isorec.name_len[0] == 1) 450 1.1 tsutsui && ( ((*pnt)->isorec.name[0] == 0) 451 1.1 tsutsui || ((*pnt)->isorec.name[0] == 1)) ) 452 1.1 tsutsui { 453 1.1 tsutsui if( (*pnt)->name != NULL ) 454 1.1 tsutsui { 455 1.1 tsutsui free((*pnt)->name); 456 1.1 tsutsui } 457 1.1 tsutsui if( (*pnt)->whole_name != NULL ) 458 1.1 tsutsui { 459 1.1 tsutsui free((*pnt)->whole_name); 460 1.1 tsutsui } 461 1.1 tsutsui if( (*pnt)->isorec.name[0] == 0 ) 462 1.1 tsutsui { 463 1.1 tsutsui (*pnt)->name = strdup("."); 464 1.1 tsutsui } 465 1.1 tsutsui else 466 1.1 tsutsui { 467 1.1 tsutsui (*pnt)->name = strdup(".."); 468 1.1 tsutsui } 469 1.1 tsutsui } 470 1.1 tsutsui 471 1.1 tsutsui #ifdef DEBUG 472 1.1 tsutsui fprintf(stderr, "got DE name: %s\n", (*pnt)->name); 473 1.1 tsutsui #endif 474 1.1 tsutsui 475 1.1 tsutsui #ifdef APPLE_HYB 476 1.1 tsutsui if( strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0) 477 1.1 tsutsui #else 478 1.1 tsutsui if( strncmp(idr->name, "TRANS.TBL", 9) == 0) 479 1.1 tsutsui #endif /* APPLE_HYB */ 480 1.1 tsutsui { 481 1.1 tsutsui if( (*pnt)->name != NULL ) 482 1.1 tsutsui { 483 1.1 tsutsui free((*pnt)->name); 484 1.1 tsutsui } 485 1.1 tsutsui if( (*pnt)->whole_name != NULL ) 486 1.1 tsutsui { 487 1.1 tsutsui free((*pnt)->whole_name); 488 1.1 tsutsui } 489 1.1 tsutsui (*pnt)->name = strdup("<translation table>"); 490 1.1 tsutsui tt_extent = isonum_733((unsigned char *)idr->extent); 491 1.1 tsutsui tt_size = isonum_733((unsigned char *)idr->size); 492 1.1 tsutsui } 493 1.1 tsutsui 494 1.1 tsutsui pnt++; 495 1.1 tsutsui i += idr->length[0]; 496 1.1 tsutsui } 497 1.1 tsutsui 498 1.1 tsutsui /* 499 1.1 tsutsui * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it 500 1.1 tsutsui * to get the filenames of the files. Also, save the table info, just 501 1.1 tsutsui * in case we need to use it. 502 1.1 tsutsui */ 503 1.1 tsutsui if( tt_extent != 0 && tt_size != 0 ) 504 1.1 tsutsui { 505 1.1 tsutsui tt_buf = (unsigned char *) e_malloc(tt_size); 506 1.1 tsutsui readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE); 507 1.1 tsutsui 508 1.1 tsutsui /* 509 1.1 tsutsui * Loop through the file, examine each entry, and attempt to 510 1.1 tsutsui * attach it to the correct entry. 511 1.1 tsutsui */ 512 1.1 tsutsui cpnt = tt_buf; 513 1.1 tsutsui cpnt1 = tt_buf; 514 1.1 tsutsui while( cpnt - tt_buf < tt_size ) 515 1.1 tsutsui { 516 1.1 tsutsui while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++; 517 1.1 tsutsui *cpnt1 = '\0'; 518 1.1 tsutsui 519 1.1 tsutsui for(pnt = rtn, i = 0; i <*nent; i++, pnt++) 520 1.1 tsutsui { 521 1.1 tsutsui rlen = isonum_711((*pnt)->isorec.name_len); 522 1.1 tsutsui if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, 523 1.1 tsutsui rlen) == 0 524 1.1 tsutsui && cpnt[2+rlen] == ' ') 525 1.1 tsutsui { 526 1.1 tsutsui (*pnt)->table = e_malloc(strlen((char*)cpnt) - 33); 527 1.1 tsutsui sprintf((*pnt)->table, "%c\t%s\n", 528 1.1 tsutsui *cpnt, cpnt+37); 529 1.1 tsutsui if( !(*pnt)->got_rr_name ) 530 1.1 tsutsui { 531 1.1 tsutsui if ((*pnt)->name != NULL) { 532 1.1 tsutsui free((*pnt)->name); 533 1.1 tsutsui } 534 1.1 tsutsui (*pnt)->name = strdup((char *) cpnt+37); 535 1.1 tsutsui } 536 1.1 tsutsui break; 537 1.1 tsutsui } 538 1.1 tsutsui } 539 1.1 tsutsui cpnt = cpnt1 + 1; 540 1.1 tsutsui cpnt1 = cpnt; 541 1.1 tsutsui } 542 1.1 tsutsui 543 1.1 tsutsui free(tt_buf); 544 1.1 tsutsui } 545 1.1 tsutsui else if( !seen_rockridge && !warning_given ) 546 1.1 tsutsui { 547 1.1 tsutsui /* 548 1.1 tsutsui * Warn the user that iso (8.3) names were used because neither 549 1.1 tsutsui * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were found. 550 1.1 tsutsui */ 551 1.1 tsutsui fprintf(stderr,"Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n"); 552 1.1 tsutsui fprintf(stderr,"name translations were found on previous session.\n"); 553 1.1 tsutsui fprintf(stderr,"ISO (8.3) file names have been used instead.\n"); 554 1.1 tsutsui warning_given = 1; 555 1.1 tsutsui } 556 1.1 tsutsui 557 1.1 tsutsui if( dirbuff != NULL ) 558 1.1 tsutsui { 559 1.1 tsutsui free(dirbuff); 560 1.1 tsutsui } 561 1.1 tsutsui 562 1.1 tsutsui return rtn; 563 1.1 tsutsui } /* read_merging_directory */ 564 1.1 tsutsui 565 1.1 tsutsui /* 566 1.1 tsutsui * Free any associated data related to the structures. 567 1.1 tsutsui */ 568 1.1 tsutsui int 569 1.1 tsutsui FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len ) 570 1.1 tsutsui { 571 1.1 tsutsui int i; 572 1.1 tsutsui struct directory_entry **p; 573 1.1 tsutsui 574 1.1 tsutsui p = ptr; 575 1.1 tsutsui for(i=0; i<len; i++, p++) 576 1.1 tsutsui { 577 1.1 tsutsui /* 578 1.1 tsutsui * If the tree-handling code decided that it needed an entry, 579 1.1 tsutsui * it will have removed it from the list. Thus we must allow 580 1.1 tsutsui * for null pointers here. 581 1.1 tsutsui */ 582 1.1 tsutsui if( *p == NULL ) 583 1.1 tsutsui { 584 1.1 tsutsui continue; 585 1.1 tsutsui } 586 1.1 tsutsui 587 1.1 tsutsui if( (*p)->name != NULL ) 588 1.1 tsutsui { 589 1.1 tsutsui free((*p)->name); 590 1.1 tsutsui } 591 1.1 tsutsui 592 1.1 tsutsui if( (*p)->whole_name != NULL ) 593 1.1 tsutsui { 594 1.1 tsutsui free((*p)->whole_name); 595 1.1 tsutsui } 596 1.1 tsutsui 597 1.1 tsutsui if( (*p)->rr_attributes != NULL ) 598 1.1 tsutsui { 599 1.1 tsutsui free((*p)->rr_attributes); 600 1.1 tsutsui } 601 1.1 tsutsui 602 1.1 tsutsui if( (*p)->table != NULL ) 603 1.1 tsutsui { 604 1.1 tsutsui free((*p)->table); 605 1.1 tsutsui } 606 1.1 tsutsui 607 1.1 tsutsui free(*p); 608 1.1 tsutsui 609 1.1 tsutsui } 610 1.1 tsutsui 611 1.1 tsutsui free(ptr); 612 1.1 tsutsui return 0; 613 1.1 tsutsui } 614 1.1 tsutsui 615 1.1 tsutsui /* 616 1.1 tsutsui * Search the list to see if we have any entries from the previous 617 1.1 tsutsui * session that match this entry. If so, copy the extent number 618 1.1 tsutsui * over so we don't bother to write it out to the new session. 619 1.1 tsutsui */ 620 1.1 tsutsui 621 1.1 tsutsui int 622 1.1 tsutsui FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len, 623 1.1 tsutsui struct directory_entry *, curr_entry, 624 1.1 tsutsui struct stat *, statbuf, struct stat *, lstatbuf, 625 1.1 tsutsui struct directory_entry **, odpnt) 626 1.1 tsutsui { 627 1.1 tsutsui int i; 628 1.1 tsutsui 629 1.1 tsutsui for( i=0; i < len; i++ ) 630 1.1 tsutsui { 631 1.1 tsutsui if( ptr[i] == NULL ) 632 1.1 tsutsui { 633 1.1 tsutsui continue; 634 1.1 tsutsui } 635 1.1 tsutsui 636 1.1 tsutsui #if 0 637 1.1 tsutsui if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 638 1.1 tsutsui && ptr[i]->name[0] == '\0' ) 639 1.1 tsutsui { 640 1.1 tsutsui continue; 641 1.1 tsutsui } 642 1.1 tsutsui if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 643 1.1 tsutsui && ptr[i]->name[0] == 1) 644 1.1 tsutsui { 645 1.1 tsutsui continue; 646 1.1 tsutsui } 647 1.1 tsutsui #else 648 1.1 tsutsui if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 ) 649 1.1 tsutsui { 650 1.1 tsutsui continue; 651 1.1 tsutsui } 652 1.1 tsutsui if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 ) 653 1.1 tsutsui { 654 1.1 tsutsui continue; 655 1.1 tsutsui } 656 1.1 tsutsui #endif 657 1.1 tsutsui 658 1.1 tsutsui if( ptr[i]->name != NULL 659 1.1 tsutsui && strcmp(ptr[i]->name, curr_entry->name) != 0 ) 660 1.1 tsutsui { 661 1.1 tsutsui continue; 662 1.1 tsutsui } 663 1.1 tsutsui 664 1.1 tsutsui /* 665 1.1 tsutsui * We know that the files have the same name. If they also have 666 1.1 tsutsui * the same file type (i.e. file, dir, block, etc), then we 667 1.1 tsutsui * can safely reuse the TRANS.TBL entry for this file. 668 1.1 tsutsui * The check_rr_dates function will do this for us. 669 1.1 tsutsui * 670 1.1 tsutsui * Verify that the file type and dates are consistent. 671 1.1 tsutsui * If not, we probably have a different file, and we need 672 1.1 tsutsui * to write it out again. 673 1.1 tsutsui */ 674 1.1 tsutsui if( (ptr[i]->rr_attributes != NULL) 675 1.1 tsutsui && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) ) 676 1.1 tsutsui { 677 1.1 tsutsui goto found_it; 678 1.1 tsutsui } 679 1.1 tsutsui 680 1.1 tsutsui 681 1.1 tsutsui /* 682 1.1 tsutsui * Verify size and timestamp. If rock ridge is in use, we need 683 1.1 tsutsui * to compare dates from RR too. Directories are special, we 684 1.1 tsutsui * calculate their size later. 685 1.1 tsutsui */ 686 1.1 tsutsui if( (curr_entry->isorec.flags[0] & 2) == 0 687 1.1 tsutsui && ptr[i]->size != curr_entry->size ) 688 1.1 tsutsui { 689 1.1 tsutsui goto found_it; 690 1.1 tsutsui } 691 1.1 tsutsui 692 1.1 tsutsui if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 ) 693 1.1 tsutsui { 694 1.1 tsutsui goto found_it; 695 1.1 tsutsui } 696 1.1 tsutsui 697 1.1 tsutsui /* 698 1.1 tsutsui * Never ever reuse directory extents. See comments in 699 1.1 tsutsui * tree.c for an explaination of why this must be the case. 700 1.1 tsutsui */ 701 1.1 tsutsui if( (curr_entry->isorec.flags[0] & 2) != 0 ) 702 1.1 tsutsui { 703 1.1 tsutsui goto found_it; 704 1.1 tsutsui } 705 1.1 tsutsui 706 1.1 tsutsui memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8); 707 1.1 tsutsui curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; 708 1.1 tsutsui goto found_it; 709 1.1 tsutsui } 710 1.1 tsutsui return 0; 711 1.1 tsutsui 712 1.1 tsutsui found_it: 713 1.1 tsutsui if( odpnt != NULL ) 714 1.1 tsutsui { 715 1.1 tsutsui *odpnt = ptr[i]; 716 1.1 tsutsui } 717 1.1 tsutsui else 718 1.1 tsutsui { 719 1.1 tsutsui free(ptr[i]); 720 1.1 tsutsui } 721 1.1 tsutsui ptr[i] = NULL; 722 1.1 tsutsui return 0; 723 1.1 tsutsui } 724 1.1 tsutsui 725 1.1 tsutsui /* 726 1.1 tsutsui * merge_isofs: Scan an existing image, and return a pointer 727 1.1 tsutsui * to the root directory for this image. 728 1.1 tsutsui */ 729 1.1 tsutsui struct iso_directory_record * FDECL1(merge_isofs, char *, path) 730 1.1 tsutsui { 731 1.1 tsutsui char buffer[SECTOR_SIZE]; 732 1.1 tsutsui int file_addr; 733 1.1 tsutsui int i; 734 1.1 tsutsui struct iso_primary_descriptor * pri = NULL; 735 1.1 tsutsui struct iso_directory_record * rootp; 736 1.1 tsutsui struct iso_volume_descriptor * vdp; 737 1.1 tsutsui 738 1.1 tsutsui /* 739 1.1 tsutsui * Start by opening up the image and searching for the volume header. 740 1.1 tsutsui * Ultimately, we need to search for volume headers in multiple places 741 1.1 tsutsui * because we might be starting with a multisession image. 742 1.1 tsutsui * FIXME(eric). 743 1.1 tsutsui */ 744 1.1 tsutsui 745 1.1 tsutsui #ifndef USE_SCG 746 1.1 tsutsui in_image = fopen(path, "rb"); 747 1.1 tsutsui if( in_image == NULL ) 748 1.1 tsutsui { 749 1.1 tsutsui return NULL; 750 1.1 tsutsui } 751 1.1 tsutsui #else 752 1.1 tsutsui if (strchr(path, '/')) { 753 1.1 tsutsui in_image = fopen(path, "rb"); 754 1.1 tsutsui if( in_image == NULL ) { 755 1.1 tsutsui return NULL; 756 1.1 tsutsui } 757 1.1 tsutsui } else { 758 1.1 tsutsui if (scsidev_open(path) < 0) 759 1.1 tsutsui return NULL; 760 1.1 tsutsui } 761 1.1 tsutsui #endif 762 1.1 tsutsui 763 1.1 tsutsui get_session_start(&file_addr); 764 1.1 tsutsui 765 1.1 tsutsui for(i = 0; i< 100; i++) 766 1.1 tsutsui { 767 1.1 tsutsui if (readsecs(file_addr/SECTOR_SIZE, &buffer, 768 1.1 tsutsui sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer)) 769 1.1 tsutsui { 770 1.1 tsutsui fprintf(stderr," Read error on old image %s\n", path); 771 1.1 tsutsui exit(10); 772 1.1 tsutsui } 773 1.1 tsutsui 774 1.1 tsutsui vdp = (struct iso_volume_descriptor *)buffer; 775 1.1 tsutsui 776 1.1 tsutsui if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) 777 1.1 tsutsui && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) ) 778 1.1 tsutsui { 779 1.1 tsutsui break; 780 1.1 tsutsui } 781 1.1 tsutsui file_addr += SECTOR_SIZE; 782 1.1 tsutsui } 783 1.1 tsutsui 784 1.1 tsutsui if( i == 100 ) 785 1.1 tsutsui { 786 1.1 tsutsui return NULL; 787 1.1 tsutsui } 788 1.1 tsutsui 789 1.1 tsutsui pri = (struct iso_primary_descriptor *)vdp; 790 1.1 tsutsui 791 1.1 tsutsui /* 792 1.1 tsutsui * Check the blocksize of the image to make sure it is compatible. 793 1.1 tsutsui */ 794 1.1 tsutsui if( (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE) 795 1.1 tsutsui || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) ) 796 1.1 tsutsui { 797 1.1 tsutsui return NULL; 798 1.1 tsutsui } 799 1.1 tsutsui 800 1.1 tsutsui /* 801 1.1 tsutsui * Get the location and size of the root directory. 802 1.1 tsutsui */ 803 1.1 tsutsui rootp = calloc(1, sizeof(struct iso_directory_record)); 804 1.1 tsutsui 805 1.1 tsutsui memcpy(rootp, pri->root_directory_record, sizeof(pri->root_directory_record)); 806 1.1 tsutsui 807 1.1 tsutsui return rootp; 808 1.1 tsutsui } 809 1.1 tsutsui 810 1.1 tsutsui void FDECL3(merge_remaining_entries, struct directory *, this_dir, 811 1.1 tsutsui struct directory_entry **, pnt, 812 1.1 tsutsui int, n_orig) 813 1.1 tsutsui { 814 1.1 tsutsui int i; 815 1.1 tsutsui struct directory_entry * s_entry; 816 1.1 tsutsui unsigned int ttbl_extent = 0; 817 1.1 tsutsui unsigned int ttbl_index = 0; 818 1.1 tsutsui char whole_path[1024]; 819 1.1 tsutsui 820 1.1 tsutsui /* 821 1.1 tsutsui * Whatever is leftover in the list needs to get merged back 822 1.1 tsutsui * into the directory. 823 1.1 tsutsui */ 824 1.1 tsutsui for( i=0; i < n_orig; i++ ) 825 1.1 tsutsui { 826 1.1 tsutsui if( pnt[i] == NULL ) 827 1.1 tsutsui { 828 1.1 tsutsui continue; 829 1.1 tsutsui } 830 1.1 tsutsui 831 1.1 tsutsui if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL) 832 1.1 tsutsui { 833 1.1 tsutsui /* 834 1.1 tsutsui * Set the name for this directory. 835 1.1 tsutsui */ 836 1.1 tsutsui strcpy(whole_path, this_dir->de_name); 837 1.1 tsutsui strcat(whole_path, SPATH_SEPARATOR); 838 1.1 tsutsui strcat(whole_path, pnt[i]->name); 839 1.1 tsutsui 840 1.1 tsutsui pnt[i]->whole_name = strdup(whole_path); 841 1.1 tsutsui } 842 1.1 tsutsui 843 1.1 tsutsui if( pnt[i]->name != NULL 844 1.1 tsutsui && strcmp(pnt[i]->name, "<translation table>") == 0 ) 845 1.1 tsutsui { 846 1.1 tsutsui ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent); 847 1.1 tsutsui ttbl_index = i; 848 1.1 tsutsui continue; 849 1.1 tsutsui } 850 1.1 tsutsui /* 851 1.1 tsutsui * Skip directories for now - these need to be treated 852 1.1 tsutsui * differently. 853 1.1 tsutsui */ 854 1.1 tsutsui if( (pnt[i]->isorec.flags[0] & 2) != 0 ) 855 1.1 tsutsui { 856 1.1 tsutsui /* 857 1.1 tsutsui * FIXME - we need to insert this directory into the 858 1.1 tsutsui * tree, so that the path tables we generate will 859 1.1 tsutsui * be correct. 860 1.1 tsutsui */ 861 1.1 tsutsui if( (strcmp(pnt[i]->name, ".") == 0) 862 1.1 tsutsui || (strcmp(pnt[i]->name, "..") == 0) ) 863 1.1 tsutsui { 864 1.1 tsutsui free(pnt[i]); 865 1.1 tsutsui pnt[i] = NULL; 866 1.1 tsutsui continue; 867 1.1 tsutsui } 868 1.1 tsutsui else 869 1.1 tsutsui { 870 1.1 tsutsui merge_old_directory_into_tree(pnt[i], this_dir); 871 1.1 tsutsui } 872 1.1 tsutsui } 873 1.1 tsutsui pnt[i]->next = this_dir->contents; 874 1.1 tsutsui pnt[i]->filedir = this_dir; 875 1.1 tsutsui this_dir->contents = pnt[i]; 876 1.1 tsutsui pnt[i] = NULL; 877 1.1 tsutsui } 878 1.1 tsutsui 879 1.1 tsutsui 880 1.1 tsutsui /* 881 1.1 tsutsui * If we don't have an entry for the translation table, then 882 1.1 tsutsui * don't bother trying to copy the starting extent over. 883 1.1 tsutsui * Note that it is possible that if we are copying the entire 884 1.1 tsutsui * directory, the entry for the translation table will have already 885 1.1 tsutsui * been inserted into the linked list and removed from the old 886 1.1 tsutsui * entries list, in which case we want to leave the extent number 887 1.1 tsutsui * as it was before. 888 1.1 tsutsui */ 889 1.1 tsutsui if( ttbl_extent == 0 ) 890 1.1 tsutsui { 891 1.1 tsutsui return; 892 1.1 tsutsui } 893 1.1 tsutsui 894 1.1 tsutsui /* 895 1.1 tsutsui * Finally, check the directory we are creating to see whether 896 1.1 tsutsui * there are any new entries in it. If there are not, we can 897 1.1 tsutsui * reuse the same translation table. 898 1.1 tsutsui */ 899 1.1 tsutsui for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 900 1.1 tsutsui { 901 1.1 tsutsui /* 902 1.1 tsutsui * Don't care about '.' or '..'. They are never in the table 903 1.1 tsutsui * anyways. 904 1.1 tsutsui */ 905 1.1 tsutsui if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 ) 906 1.1 tsutsui { 907 1.1 tsutsui continue; 908 1.1 tsutsui } 909 1.1 tsutsui if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 ) 910 1.1 tsutsui { 911 1.1 tsutsui continue; 912 1.1 tsutsui } 913 1.1 tsutsui if( strcmp(s_entry->name, "<translation table>") == 0) 914 1.1 tsutsui { 915 1.1 tsutsui continue; 916 1.1 tsutsui } 917 1.1 tsutsui if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 ) 918 1.1 tsutsui { 919 1.1 tsutsui return; 920 1.1 tsutsui } 921 1.1 tsutsui } 922 1.1 tsutsui 923 1.1 tsutsui /* 924 1.1 tsutsui * Locate the translation table, and re-use the same extent. 925 1.1 tsutsui * It isn't clear that there should ever be one in there already 926 1.1 tsutsui * so for now we try and muddle through the best we can. 927 1.1 tsutsui */ 928 1.1 tsutsui for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 929 1.1 tsutsui { 930 1.1 tsutsui if( strcmp(s_entry->name, "<translation table>") == 0) 931 1.1 tsutsui { 932 1.1 tsutsui fprintf(stderr,"Should never get here\n"); 933 1.1 tsutsui set_733(s_entry->isorec.extent, ttbl_extent); 934 1.1 tsutsui return; 935 1.1 tsutsui } 936 1.1 tsutsui } 937 1.1 tsutsui 938 1.1 tsutsui pnt[ttbl_index]->next = this_dir->contents; 939 1.1 tsutsui pnt[ttbl_index]->filedir = this_dir; 940 1.1 tsutsui this_dir->contents = pnt[ttbl_index]; 941 1.1 tsutsui pnt[ttbl_index] = NULL; 942 1.1 tsutsui } 943 1.1 tsutsui 944 1.1 tsutsui 945 1.1 tsutsui /* 946 1.1 tsutsui * Here we have a case of a directory that has completely disappeared from 947 1.1 tsutsui * the face of the earth on the tree we are mastering from. Go through and 948 1.1 tsutsui * merge it into the tree, as well as everything beneath it. 949 1.1 tsutsui * 950 1.1 tsutsui * Note that if a directory has been moved for some reason, this will 951 1.1 tsutsui * incorrectly pick it up and attempt to merge it back into the old 952 1.1 tsutsui * location. FIXME(eric). 953 1.1 tsutsui */ 954 1.1 tsutsui static int 955 1.1 tsutsui FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, 956 1.1 tsutsui struct directory *, parent) 957 1.1 tsutsui { 958 1.1 tsutsui struct directory_entry **contents = NULL; 959 1.1 tsutsui int i; 960 1.1 tsutsui int n_orig; 961 1.1 tsutsui struct directory * this_dir, *next_brother; 962 1.1 tsutsui char whole_path[1024]; 963 1.1 tsutsui 964 1.1 tsutsui this_dir = (struct directory *) e_malloc(sizeof(struct directory)); 965 1.1 tsutsui memset(this_dir, 0, sizeof(struct directory)); 966 1.1 tsutsui this_dir->next = NULL; 967 1.1 tsutsui this_dir->subdir = NULL; 968 1.1 tsutsui this_dir->self = dpnt; 969 1.1 tsutsui this_dir->contents = NULL; 970 1.1 tsutsui this_dir->size = 0; 971 1.1 tsutsui this_dir->extent = 0; 972 1.1 tsutsui this_dir->depth = parent->depth + 1; 973 1.1 tsutsui this_dir->parent = parent; 974 1.1 tsutsui if(!parent->subdir) 975 1.1 tsutsui parent->subdir = this_dir; 976 1.1 tsutsui else { 977 1.1 tsutsui next_brother = parent->subdir; 978 1.1 tsutsui while(next_brother->next) next_brother = next_brother->next; 979 1.1 tsutsui next_brother->next = this_dir; 980 1.1 tsutsui } 981 1.1 tsutsui 982 1.1 tsutsui /* 983 1.1 tsutsui * Set the name for this directory. 984 1.1 tsutsui */ 985 1.1 tsutsui strcpy(whole_path, parent->de_name); 986 1.1 tsutsui strcat(whole_path, SPATH_SEPARATOR); 987 1.1 tsutsui strcat(whole_path, dpnt->name); 988 1.1 tsutsui this_dir->de_name = strdup(whole_path); 989 1.1 tsutsui this_dir->whole_name = strdup(whole_path); 990 1.1 tsutsui 991 1.1 tsutsui /* 992 1.1 tsutsui * Now fill this directory using information from the previous 993 1.1 tsutsui * session. 994 1.1 tsutsui */ 995 1.1 tsutsui contents = read_merging_directory(&dpnt->isorec, &n_orig); 996 1.1 tsutsui /* 997 1.1 tsutsui * Start by simply copying the '.', '..' and non-directory 998 1.1 tsutsui * entries to this directory. Technically we could let 999 1.1 tsutsui * merge_remaining_entries handle this, but it gets rather confused 1000 1.1 tsutsui * by the '.' and '..' entries. 1001 1.1 tsutsui */ 1002 1.1 tsutsui for(i=0; i < n_orig; i ++ ) 1003 1.1 tsutsui { 1004 1.1 tsutsui /* 1005 1.1 tsutsui * We can always reuse the TRANS.TBL in this particular case. 1006 1.1 tsutsui */ 1007 1.1 tsutsui contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; 1008 1.1 tsutsui 1009 1.1 tsutsui if( ((contents[i]->isorec.flags[0] & 2) != 0) 1010 1.1 tsutsui && (i >= 2) ) 1011 1.1 tsutsui { 1012 1.1 tsutsui continue; 1013 1.1 tsutsui } 1014 1.1 tsutsui 1015 1.1 tsutsui /* 1016 1.1 tsutsui * If we have a directory, don't reuse the extent number. 1017 1.1 tsutsui */ 1018 1.1 tsutsui if( (contents[i]->isorec.flags[0] & 2) != 0 ) 1019 1.1 tsutsui { 1020 1.1 tsutsui memset(contents[i]->isorec.extent, 0, 8); 1021 1.1 tsutsui 1022 1.1 tsutsui if( strcmp(contents[i]->name, ".") == 0 ) 1023 1.1 tsutsui this_dir->dir_flags |= DIR_HAS_DOT; 1024 1.1 tsutsui 1025 1.1 tsutsui if( strcmp(contents[i]->name, "..") == 0 ) 1026 1.1 tsutsui this_dir->dir_flags |= DIR_HAS_DOTDOT; 1027 1.1 tsutsui } 1028 1.1 tsutsui 1029 1.1 tsutsui /* 1030 1.1 tsutsui * Set the whole name for this file. 1031 1.1 tsutsui */ 1032 1.1 tsutsui strcpy(whole_path, this_dir->whole_name); 1033 1.1 tsutsui strcat(whole_path, SPATH_SEPARATOR); 1034 1.1 tsutsui strcat(whole_path, contents[i]->name); 1035 1.1 tsutsui 1036 1.1 tsutsui contents[i]->whole_name = strdup(whole_path); 1037 1.1 tsutsui 1038 1.1 tsutsui contents[i]->next = this_dir->contents; 1039 1.1 tsutsui contents[i]->filedir = this_dir; 1040 1.1 tsutsui this_dir->contents = contents[i]; 1041 1.1 tsutsui contents[i] = NULL; 1042 1.1 tsutsui } 1043 1.1 tsutsui 1044 1.1 tsutsui /* 1045 1.1 tsutsui * Zero the extent number for ourselves. 1046 1.1 tsutsui */ 1047 1.1 tsutsui memset(dpnt->isorec.extent, 0, 8); 1048 1.1 tsutsui 1049 1.1 tsutsui /* 1050 1.1 tsutsui * Anything that is left are other subdirectories that need to be merged. 1051 1.1 tsutsui */ 1052 1.1 tsutsui merge_remaining_entries(this_dir, contents, n_orig); 1053 1.1 tsutsui free_mdinfo(contents, n_orig); 1054 1.1 tsutsui #if 0 1055 1.1 tsutsui /* 1056 1.1 tsutsui * This is no longer required. The post-scan sort will handle 1057 1.1 tsutsui * all of this for us. 1058 1.1 tsutsui */ 1059 1.1 tsutsui sort_n_finish(this_dir); 1060 1.1 tsutsui #endif 1061 1.1 tsutsui 1062 1.1 tsutsui return 0; 1063 1.1 tsutsui } 1064 1.1 tsutsui 1065 1.1 tsutsui 1066 1.1 tsutsui char * cdwrite_data = NULL; 1067 1.1 tsutsui 1068 1.1 tsutsui int 1069 1.1 tsutsui FDECL1(get_session_start, int *, file_addr) 1070 1.1 tsutsui { 1071 1.1 tsutsui char * pnt; 1072 1.1 tsutsui 1073 1.1 tsutsui #ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS 1074 1.1 tsutsui /* 1075 1.1 tsutsui * FIXME(eric). We need to coordinate with cdwrite to obtain 1076 1.1 tsutsui * the parameters. For now, we assume we are writing the 2nd session, 1077 1.1 tsutsui * so we start from the session that starts at 0. 1078 1.1 tsutsui */ 1079 1.1 tsutsui 1080 1.1 tsutsui *file_addr = (16 << 11); 1081 1.1 tsutsui 1082 1.1 tsutsui /* 1083 1.1 tsutsui * We need to coordinate with cdwrite to get the next writable address 1084 1.1 tsutsui * from the device. Here is where we use it. 1085 1.1 tsutsui */ 1086 1.1 tsutsui session_start = last_extent = last_extent_written = cdwrite_result(); 1087 1.1 tsutsui 1088 1.1 tsutsui #else 1089 1.1 tsutsui 1090 1.1 tsutsui if( cdwrite_data == NULL ) 1091 1.1 tsutsui { 1092 1.1 tsutsui fprintf(stderr,"Special parameters for cdwrite not specified with -C\n"); 1093 1.1 tsutsui exit(1); 1094 1.1 tsutsui } 1095 1.1 tsutsui 1096 1.1 tsutsui /* 1097 1.1 tsutsui * Next try and find the ',' in there which delimits the two numbers. 1098 1.1 tsutsui */ 1099 1.1 tsutsui pnt = strchr(cdwrite_data, ','); 1100 1.1 tsutsui if( pnt == NULL ) 1101 1.1 tsutsui { 1102 1.1 tsutsui fprintf(stderr, "Malformed cdwrite parameters\n"); 1103 1.1 tsutsui exit(1); 1104 1.1 tsutsui } 1105 1.1 tsutsui 1106 1.1 tsutsui *pnt = '\0'; 1107 1.1 tsutsui if (file_addr != NULL) { 1108 1.1 tsutsui *file_addr = atol(cdwrite_data) * SECTOR_SIZE; 1109 1.1 tsutsui } 1110 1.1 tsutsui pnt++; 1111 1.1 tsutsui 1112 1.1 tsutsui session_start = last_extent = last_extent_written = atol(pnt); 1113 1.1 tsutsui 1114 1.1 tsutsui pnt--; 1115 1.1 tsutsui *pnt = ','; 1116 1.1 tsutsui 1117 1.1 tsutsui #endif 1118 1.1 tsutsui return 0; 1119 1.1 tsutsui } 1120 1.1 tsutsui 1121 1.1 tsutsui /* 1122 1.1 tsutsui * This function scans the directory tree, looking for files, and it makes 1123 1.1 tsutsui * note of everything that is found. We also begin to construct the ISO9660 1124 1.1 tsutsui * directory entries, so that we can determine how large each directory is. 1125 1.1 tsutsui */ 1126 1.1 tsutsui 1127 1.1 tsutsui int 1128 1.1 tsutsui FDECL2(merge_previous_session,struct directory *, this_dir, 1129 1.1 tsutsui struct iso_directory_record *, mrootp) 1130 1.1 tsutsui { 1131 1.1 tsutsui struct directory_entry **orig_contents = NULL; 1132 1.1 tsutsui struct directory_entry * odpnt = NULL; 1133 1.1 tsutsui int n_orig; 1134 1.1 tsutsui struct directory_entry * s_entry; 1135 1.1 tsutsui int status, lstatus; 1136 1.1 tsutsui struct stat statbuf, lstatbuf; 1137 1.1 tsutsui 1138 1.1 tsutsui /* 1139 1.1 tsutsui * Parse the same directory in the image that we are merging 1140 1.1 tsutsui * for multisession stuff. 1141 1.1 tsutsui */ 1142 1.1 tsutsui orig_contents = read_merging_directory(mrootp, &n_orig); 1143 1.1 tsutsui if( orig_contents == NULL ) 1144 1.1 tsutsui { 1145 1.1 tsutsui return 0; 1146 1.1 tsutsui } 1147 1.1 tsutsui 1148 1.1 tsutsui 1149 1.1 tsutsui /* Now we scan the directory itself, and look at what is inside of it. */ 1150 1.1 tsutsui 1151 1.1 tsutsui for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 1152 1.1 tsutsui { 1153 1.1 tsutsui status = stat_filter(s_entry->whole_name, &statbuf); 1154 1.1 tsutsui lstatus = lstat_filter(s_entry->whole_name, &lstatbuf); 1155 1.1 tsutsui 1156 1.1 tsutsui /* 1157 1.1 tsutsui * We always should create an entirely new directory tree whenever 1158 1.1 tsutsui * we generate a new session, unless there were *no* changes whatsoever 1159 1.1 tsutsui * to any of the directories, in which case it would be kind of pointless 1160 1.1 tsutsui * to generate a new session. 1161 1.1 tsutsui * 1162 1.1 tsutsui * I believe it is possible to rigorously prove that any change anywhere 1163 1.1 tsutsui * in the filesystem will force the entire tree to be regenerated 1164 1.1 tsutsui * because the modified directory will get a new extent number. Since 1165 1.1 tsutsui * each subdirectory of the changed directory has a '..' entry, all of 1166 1.1 tsutsui * them will need to be rewritten too, and since the parent directory 1167 1.1 tsutsui * of the modified directory will have an extent pointer to the directory 1168 1.1 tsutsui * it too will need to be rewritten. Thus we will never be able to reuse 1169 1.1 tsutsui * any directory information when writing new sessions. 1170 1.1 tsutsui * 1171 1.1 tsutsui * We still check the previous session so we can mark off the equivalent 1172 1.1 tsutsui * entry in the list we got from the original disc, however. 1173 1.1 tsutsui */ 1174 1.1 tsutsui 1175 1.1 tsutsui /* 1176 1.1 tsutsui * The check_prev_session function looks for an identical entry in 1177 1.1 tsutsui * the previous session. If we see it, then we copy the extent 1178 1.1 tsutsui * number to s_entry, and cross it off the list. 1179 1.1 tsutsui */ 1180 1.1 tsutsui check_prev_session(orig_contents, n_orig, s_entry, 1181 1.1 tsutsui &statbuf, &lstatbuf, &odpnt); 1182 1.1 tsutsui 1183 1.1 tsutsui if(S_ISDIR(statbuf.st_mode) && odpnt != NULL) 1184 1.1 tsutsui { 1185 1.1 tsutsui int dflag; 1186 1.1 tsutsui 1187 1.1 tsutsui if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 1188 1.1 tsutsui { 1189 1.1 tsutsui struct directory * child; 1190 1.1 tsutsui 1191 1.1 tsutsui child = find_or_create_directory(this_dir, 1192 1.1 tsutsui s_entry->whole_name, 1193 1.1 tsutsui s_entry, 1); 1194 1.1 tsutsui dflag = merge_previous_session(child, 1195 1.1 tsutsui &odpnt->isorec); 1196 1.1 tsutsui /* If unable to scan directory, mark this as a non-directory */ 1197 1.1 tsutsui if(!dflag) 1198 1.1 tsutsui lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; 1199 1.1 tsutsui free(odpnt); 1200 1.1 tsutsui odpnt = NULL; 1201 1.1 tsutsui } 1202 1.1 tsutsui } 1203 1.1 tsutsui } 1204 1.1 tsutsui 1205 1.1 tsutsui /* 1206 1.1 tsutsui * Whatever is left over, are things which are no longer in the tree 1207 1.1 tsutsui * on disk. We need to also merge these into the tree. 1208 1.1 tsutsui */ 1209 1.1 tsutsui merge_remaining_entries(this_dir, orig_contents, n_orig); 1210 1.1 tsutsui free_mdinfo(orig_contents, n_orig); 1211 1.1 tsutsui 1212 1.1 tsutsui return 1; 1213 1.1 tsutsui } 1214 1.1 tsutsui 1215