int rd_sync(void) { int errcnt = 0; int res; /* * if the user says bail out on first fault, we are out of here... */ if (maxflt == 0) return(-1); if (act == APPND) { paxwarn(1, "Unable to append when there are archive read errors."); return(-1); } /* * poke at device and try to get past media error */ if (ar_rdsync() < 0) { if (ar_next() < 0) return(-1); else rdcnt = 0; } for (;;) { if ((res = ar_read(buf, blksz)) > 0) { /* * All right! got some data, fill that buffer */ bufpt = buf; bufend = buf + res; rdcnt += res; return(0); } /* * Oh well, yet another failed read... * if error limit reached, ditch. o.w. poke device to move past * bad media and try again. if media is badly damaged, we ask * the poor (and upset user at this point) for the next archive * volume. remember the goal on reads is to get the most we * can extract out of the archive. */ if ((maxflt > 0) && (++errcnt > maxflt)) paxwarn(0,"Archive read error limit (%d) reached",maxflt); else if (ar_rdsync() == 0) continue; if (ar_next() < 0) break; rdcnt = 0; errcnt = 0; } return(-1); }
int rd_start() #endif { /* * leave space for the header pushback (see get_arc()). If we are * going to append and user specified a write block size, check it * right away */ buf = &(bufmem[BLKMULT]); if ((act == APPND) && wrblksz) { if (wrblksz > MAXBLK) { warn(1,"Write block size %d too large, maximium is: %d", wrblksz, MAXBLK); return(-1); } if (wrblksz % BLKMULT) { warn(1, "Write block size %d is not a %d byte multiple", wrblksz, BLKMULT); return(-1); } } /* * open the archive */ if ((ar_open(arcname) < 0) && (ar_next() < 0)) return(-1); bufend = buf + rdblksz; bufpt = bufend; rdcnt = 0; return(0); }
int buf_fill(void) { int cnt; static int fini = 0; if (fini) return(0); for (;;) { /* * try to fill the buffer. on error the next archive volume is * opened and we try again. */ if ((cnt = ar_read(buf, blksz)) > 0) { bufpt = buf; bufend = buf + cnt; rdcnt += cnt; return(cnt); } /* * errors require resync, EOF goes to next archive */ if (cnt < 0) break; if (ar_next() < 0) { fini = 1; return(0); } rdcnt = 0; } exit_val = 1; return(-1); }
/* scan an archive of Mach-Os */ static int scanmacho_archive(const char *filename, int fd, size_t len) { archive_handle *ar; archive_member *m; char *ar_buffer; fatobj *fobj; fatobj *walk; ar = ar_open_fd(filename, fd); if (ar == NULL) return 1; ar_buffer = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0); while ((m = ar_next(ar)) != NULL) { fobj = readmacho_buffer(m->name, ar_buffer + lseek(fd, 0, SEEK_CUR), m->size); if (fobj) { walk = fobj; do { scanmacho_fatobj(walk); } while (walk->next != NULL && (walk = walk->next)); fobj->data = NULL; unreadmacho(fobj); } } munmap(ar_buffer, len); return 0; }
int wr_start() #endif { buf = &(bufmem[BLKMULT]); /* * Check to make sure the write block size meets pax specs. If the user * does not specify a blocksize, we use the format default blocksize. * We must be picky on writes, so we do not allow the user to create an * archive that might be hard to read elsewhere. If all ok, we then * open the first archive volume */ if (!wrblksz) wrblksz = frmt->bsz; if (wrblksz > MAXBLK) { paxwarn(1, "Write block size of %d too large, maximium is: %d", wrblksz, MAXBLK); return(-1); } if (wrblksz % BLKMULT) { paxwarn(1, "Write block size of %d is not a %d byte multiple", wrblksz, BLKMULT); return(-1); } if (wrblksz > MAXBLK_POSIX) { paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable", wrblksz, MAXBLK_POSIX); return(-1); } /* * we only allow wrblksz to be used with all archive operations */ blksz = rdblksz = wrblksz; if ((ar_open(arcname) < 0) && (ar_next() < 0)) return(-1); wrcnt = 0; bufend = buf + wrblksz; bufpt = buf; return(0); }
unsigned long AddModule(unsigned long mod_start, unsigned long mod_end, unsigned long end) { char *p = (char *)mod_start; if (p[0] == 0x7f && p[1] == 'E' && p[2] == 'L' && p[3] == 'F') { /* * The loaded file is an ELF object. It may be put directly into our list of modules. * Unfortunately GRUB doesn't give us names of loaded modules */ struct ELFNode *mo = module_prepare(NULL); mo->Name = "Kickstart ELF"; mo->eh = (void*)mod_start; D(kprintf("[BOOT] * ELF module %s @ %p\n", mo->Name, mo->eh)); if (mod_end > end) end = mod_end; } else if (p[0] == 'P' && p[1] == 'K' && p[2] == 'G' && p[3] == 0x01) { /* * The loaded file is an PKG\0 archive. Scan it to find all modules which are * stored here. */ void *file = p + 8; D(kprintf("[BOOT] * package @ %p:\n", mod_start)); while (file < (void*)mod_end) { int len = LONG2BE(*(int *)file); char *s = __bs_remove_path(file+4); struct ELFNode *mo = module_prepare(s); file += 5+len; len = LONG2BE(*(int *)file); file += 4; mo->Name = s; mo->eh = file; D(kprintf("[BOOT] * PKG module %s @ %p\n", mo->Name, mo->eh)); file += len; } if (mod_end > end) end = mod_end; } else if (memcmp(p,"!<arch>\n",8) == 0) { const struct ar_header *file; char *name; const struct ar_header *longnames = NULL; /* ar(1) archive */ D(kprintf("[BOOT] * archive @ %p:\n", mod_start)); /* Look for the GNU extended name section */ for (file = (void *)(p + 8); (void *)file < (void*)mod_end; file = ar_next(file)) { name = ar_name(file, NULL); if (strcmp(name, "//") == 0) { longnames = file; break; } } D(kprintf("[BOOT] * longnames @ %p\n", longnames)); for (file = (void *)(p + 8); (void *)file < (void*)mod_end; file = ar_next(file)) { const char *data = ar_data(file); char *s = ar_name(file, longnames); if (memcmp(data,"\177ELF",4) == 0) { struct ELFNode *mo = module_prepare(s); mo->Name = s; mo->eh = (void *)data; D(kprintf("[BOOT] * ar module %s @ %p\n", mo->Name, mo->eh)); } else { D(kprintf("[BOOT] * Ignored @ %p (%s)\n", file, s)); } } if (mod_end > end) end = mod_end; } else kprintf("[BOOT] Unknown module 0x%p\n", p); return end; }
int buf_flush(int bufcnt) { int cnt; int push = 0; int totcnt = 0; /* * if we have reached the user specified byte count for each archive * volume, prompt for the next volume. (The non-standard -R flag). * NOTE: If the wrlimit is smaller than wrcnt, we will always write * at least one record. We always round limit UP to next blocksize. */ if ((wrlimit > 0) && (wrcnt > wrlimit)) { paxwarn(0, "User specified archive volume byte limit reached."); if (ar_next() < 0) { wrcnt = 0; exit_val = 1; return(-1); } wrcnt = 0; /* * The new archive volume might have changed the size of the * write blocksize. if so we figure out if we need to write * (one or more times), or if there is now free space left in * the buffer (it is no longer full). bufcnt has the number of * bytes in the buffer, (the blocksize, at the point we were * CALLED). Push has the amount of "extra" data in the buffer * if the block size has shrunk from a volume change. */ bufend = buf + blksz; if (blksz > bufcnt) return(0); if (blksz < bufcnt) push = bufcnt - blksz; } /* * We have enough data to write at least one archive block */ for (;;) { /* * write a block and check if it all went out ok */ cnt = ar_write(buf, blksz); if (cnt == blksz) { /* * the write went ok */ wrcnt += cnt; totcnt += cnt; if (push > 0) { /* we have extra data to push to the front. * check for more than 1 block of push, and if * so we loop back to write again */ memcpy(buf, bufend, push); bufpt = buf + push; if (push >= blksz) { push -= blksz; continue; } } else bufpt = buf; return(totcnt); } else if (cnt > 0) { /* * Oh drat we got a partial write! * if format does not care about alignment let it go, * we warned the user in ar_write().... but this means * the last record on this volume violates pax spec.... */ totcnt += cnt; wrcnt += cnt; bufpt = buf + cnt; cnt = bufcnt - cnt; memcpy(buf, bufpt, cnt); bufpt = buf + cnt; if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0)) return(totcnt); break; } /* * All done, go to next archive */ wrcnt = 0; if (ar_next() < 0) break; /* * The new archive volume might also have changed the block * size. if so, figure out if we have too much or too little * data for using the new block size */ bufend = buf + blksz; if (blksz > bufcnt) return(0); if (blksz < bufcnt) push = bufcnt - blksz; } /* * write failed, stop pax. we must not create a bad archive! */ exit_val = 1; return(-1); }