/* * Read a tar file and extract or list the specified files within it. * If the list is empty than all files are extracted or listed. */ static void readTarFile(int fileCount, const char ** fileTable) { const char * cp; int cc; int inCc; int blockSize; char buf[BUF_SIZE]; skipFileFlag = FALSE; badHeader = FALSE; warnedRoot = FALSE; eofFlag = FALSE; inHeader = TRUE; inCc = 0; dataCc = 0; outFd = -1; blockSize = sizeof(buf); cp = buf; /* * Open the tar file for reading. */ tarFd = open(tarName, O_RDONLY); if (tarFd < 0) { perror(tarName); return; } /* * Read blocks from the file until an end of file header block * has been seen. (A real end of file from a read is an error.) */ while (!intFlag && !eofFlag) { /* * Read the next block of data if necessary. * This will be a large block if possible, which we will * then process in the small tar blocks. */ if (inCc <= 0) { cp = buf; inCc = fullRead(tarFd, buf, blockSize); if (inCc < 0) { perror(tarName); goto done; } if (inCc == 0) { fprintf(stderr, "Unexpected end of file from \"%s\"", tarName); goto done; } } /* * If we are expecting a header block then examine it. */ if (inHeader) { readHeader((const TarHeader *) cp, fileCount, fileTable); cp += TAR_BLOCK_SIZE; inCc -= TAR_BLOCK_SIZE; continue; } /* * We are currently handling the data for a file. * Process the minimum of the amount of data we have available * and the amount left to be processed for the file. */ cc = inCc; if (cc > dataCc) cc = dataCc; readData(cp, cc); /* * If the amount left isn't an exact multiple of the tar block * size then round it up to the next block boundary since there * is padding at the end of the file. */ if (cc % TAR_BLOCK_SIZE) cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE); cp += cc; inCc -= cc; } /* * Check for an interrupt. */ if (intFlag) fprintf(stderr, "Interrupted - aborting\n"); done: /* * Close the tar file if needed. */ if ((tarFd >= 0) && (close(tarFd) < 0)) perror(tarName); /* * Close the output file if needed. * This is only done here on a previous error and so no * message is required on errors. */ if (outFd >= 0) (void) close(outFd); }
/* * Save a regular file to the tar file. */ static void saveRegularFile(const char * fileName, const struct stat * statbuf) { BOOL sawEof; int fileFd; int cc; int dataCount; long fullDataCount; char data[TAR_BLOCK_SIZE * 16]; /* * Open the file for reading. */ fileFd = open(fileName, O_RDONLY); if (fileFd < 0) { perror(fileName); return; } /* * Write out the header for the file. */ writeHeader(fileName, statbuf); /* * Write the data blocks of the file. * We must be careful to write the amount of data that the stat * buffer indicated, even if the file has changed size. Otherwise * the tar file will be incorrect. */ fullDataCount = statbuf->st_size; sawEof = FALSE; while (!intFlag && (fullDataCount > 0)) { /* * Get the amount to write this iteration which is * the minumum of the amount left to write and the * buffer size. */ dataCount = sizeof(data); if (dataCount > fullDataCount) dataCount = (int) fullDataCount; /* * Read the data from the file if we haven't seen the * end of file yet. */ cc = 0; if (!sawEof) { cc = fullRead(fileFd, data, dataCount); if (cc < 0) { perror(fileName); (void) close(fileFd); errorFlag = TRUE; return; } /* * If the file ended too soon, complain and set * a flag so we will zero fill the rest of it. */ if (cc < dataCount) { fprintf(stderr, "%s: Short read - zero filling", fileName); sawEof = TRUE; } } /* * Zero fill the rest of the data if necessary. */ if (cc < dataCount) memset(data + cc, 0, dataCount - cc); /* * Write the buffer to the TAR file. */ writeTarBlock(data, dataCount); fullDataCount -= dataCount; } /* * Close the file. */ if (close(fileFd) < 0) fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno)); }
static sys_return_t sud_get_common (az_allocid_t allocid, const char *name, char *buf, size_t len, uint64_t expectedRevision) { char fname[256]; int rv = 0; ssize_t sz = 0; int fd; int flags; assert (len >= 8); snprintf (fname, sizeof(fname)-1, "%s/%ld/%s", SUD_DIR, allocid, name); flags = OPEN_RDONLY_FLAGS; fd = MY_OPEN (fname, flags, 0); if (fd < 0) { // Handle the normal case of an invalid allocid being requested. if (errno == ENOENT) { return SYSERR_NOT_FOUND; } // All other errors are catastrophic. perror ("open"); syslog (LOG_ERR, "ERROR: sud open"); assert (0); } // Read in the revision number first. sz = fullRead (fd, buf, 8); if (sz != 8) { perror ("read 1"); syslog (LOG_ERR, "ERROR: sud read 1"); assert (0); } uint64_t actualRevision = *((uint64_t *) buf); if (expectedRevision != actualRevision) { // This is a normal condition. Return an error and allow the // caller to try again with a different expectedRevision. rv = MY_CLOSE (fd); if (rv < 0) { perror ("close"); syslog (LOG_ERR, "ERROR: sud close"); } return SYSERR_INVALID_STATE; } // Read the remainder of the record after the revision number. sz = fullRead (fd, buf+8, len-8); if ((size_t)sz != (len-8)) { perror ("read 2"); syslog (LOG_ERR, "ERROR: sud read 2"); assert (0); } rv = MY_CLOSE (fd); if (rv < 0) { perror ("close"); syslog (LOG_ERR, "ERROR: sud close"); } return SYSERR_NONE; }