📄 chunker.c
字号:
*pc = '/'; if ((outfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) { int save_errno = errno; errstr = squotef(_("holding file \"%s\": %s"), tmp_filename, strerror(errno)); amfree(tmp_filename); aclose(infd); if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)use); return -2; } else { return -1; } } amfree(tmp_filename); databuf_init(db, outfd, filename, use, chunksize); db->filename_seq++; return infd;}static intdo_chunk( int infd, struct databuf * db){ ssize_t nread; char header_buf[DISK_BLOCK_BYTES]; startclock(); dumpsize = dumpbytes = filesize = (off_t)0; headersize = 0; memset(header_buf, 0, sizeof(header_buf)); /* * The first thing we should receive is the file header, which we * need to save into "file", as well as write out. Later, the * chunk code will rewrite it. */ nread = fullread(infd, header_buf, SIZEOF(header_buf)); if (nread != DISK_BLOCK_BYTES) { if(nread < 0) { errstr = vstrallocf(_("cannot read header: %s"), strerror(errno)); } else { errstr = vstrallocf(_("cannot read header: got %zd bytes instead of %d"), nread, DISK_BLOCK_BYTES); } return 0; } parse_file_header(header_buf, &file, (size_t)nread); if(write_tapeheader(db->fd, &file)) { int save_errno = errno; errstr = squotef(_("write_tapeheader file %s: %s"), db->filename, strerror(errno)); if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); } return 0; } dumpsize += (off_t)DISK_BLOCK_KB; filesize = (off_t)DISK_BLOCK_KB; headersize += DISK_BLOCK_KB; /* * We've written the file header. Now, just write data until the * end. */ while ((nread = fullread(infd, db->buf, (size_t)(db->datalimit - db->datain))) > 0) { db->datain += nread; while(db->dataout < db->datain) { if(!databuf_flush(db)) { return 0; } } } while(db->dataout < db->datain) { if(!databuf_flush(db)) { return 0; } } if(dumpbytes > (off_t)0) { dumpsize += (off_t)1; /* count partial final KByte */ filesize += (off_t)1; } return 1;}/* * Initialize a databuf. Takes a writeable file descriptor. */static voiddatabuf_init( struct databuf * db, int fd, char * filename, off_t use, off_t chunk_size){ db->fd = fd; db->filename = stralloc(filename); db->filename_seq = (off_t)0; db->chunk_size = chunk_size; db->split_size = (db->chunk_size > use) ? use : db->chunk_size; db->use = (use > db->split_size) ? use - db->split_size : (off_t)0; db->datain = db->dataout = db->buf; db->datalimit = db->buf + SIZEOF(db->buf);}/* * Write out the buffer to the backing file */static intdatabuf_flush( struct databuf * db){ struct cmdargs cmdargs; int rc = 1; ssize_t written; off_t left_in_chunk; char *arg_filename = NULL; char *qarg_filename = NULL; char *new_filename = NULL; char *tmp_filename = NULL; char sequence[NUM_STR_SIZE]; int newfd; filetype_t save_type; char *q; int a; char *pc; /* * If there's no data, do nothing. */ if (db->dataout >= db->datain) { goto common_exit; } /* * See if we need to split this file. */ while (db->split_size > (off_t)0 && dumpsize >= db->split_size) { if( db->use == (off_t)0 ) { /* * Probably no more space on this disk. Request some more. */ cmd_t cmd; putresult(RQ_MORE_DISK, "%s\n", handle); cmd = getcmd(&cmdargs); if(command_in_transit == -1 && (cmd == DONE || cmd == TRYAGAIN || cmd == FAILED)) { command_in_transit = cmd; cmd = getcmd(&cmdargs); } if(cmd == CONTINUE) { /* * CONTINUE * serial * filename * chunksize * use */ cmdargs.argc++; /* true count of args */ a = 3; if(a >= cmdargs.argc) { error(_("error [chunker CONTINUE: not enough args: filename]")); /*NOTREACHED*/ } qarg_filename = newstralloc(qarg_filename, cmdargs.argv[a++]); if (arg_filename != NULL) amfree(arg_filename); arg_filename = unquote_string(qarg_filename); if(a >= cmdargs.argc) { error(_("error [chunker CONTINUE: not enough args: chunksize]")); /*NOTREACHED*/ } db->chunk_size = OFF_T_ATOI(cmdargs.argv[a++]); db->chunk_size = am_floor(db->chunk_size, (off_t)DISK_BLOCK_KB); if(a >= cmdargs.argc) { error(_("error [chunker CONTINUE: not enough args: use]")); /*NOTREACHED*/ } db->use = OFF_T_ATOI(cmdargs.argv[a++]); if(a != cmdargs.argc) { error(_("error [chunker CONTINUE: too many args: %d != %d]"), cmdargs.argc, a); /*NOTREACHED*/ } if(strcmp(db->filename, arg_filename) == 0) { /* * Same disk, so use what room is left up to the * next chunk boundary or the amount we were given, * whichever is less. */ left_in_chunk = db->chunk_size - filesize; if(left_in_chunk > db->use) { db->split_size += db->use; db->use = (off_t)0; } else { db->split_size += left_in_chunk; db->use -= left_in_chunk; } if(left_in_chunk > (off_t)0) { /* * We still have space in this chunk. */ break; } } else { /* * Different disk, so use new file. */ db->filename = newstralloc(db->filename, arg_filename); } } else if(cmd == ABORT) { abort_pending = 1; errstr = newstralloc(errstr, "ERROR"); putresult(ABORT_FINISHED, "%s\n", handle); rc = 0; goto common_exit; } else { if(cmdargs.argc >= 1) { q = squote(cmdargs.argv[1]); } else if(cmdargs.argc >= 0) { q = squote(cmdargs.argv[0]); } else { q = stralloc(_("(no input?)")); } error(_("error [bad command after RQ-MORE-DISK: \"%s\"]"), q); /*NOTREACHED*/ } } /* * Time to use another file. */ /* * First, open the new chunk file, and give it a new header * that has no cont_filename pointer. */ g_snprintf(sequence, SIZEOF(sequence), "%d", db->filename_seq); new_filename = newvstralloc(new_filename, db->filename, ".", sequence, NULL); tmp_filename = newvstralloc(tmp_filename, new_filename, ".tmp", NULL); pc = strrchr(tmp_filename, '/'); *pc = '\0'; mkholdingdir(tmp_filename); *pc = '/'; newfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600); if (newfd == -1) { int save_errno = errno; if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); db->use = (off_t)0; /* force RQ_MORE_DISK */ db->split_size = dumpsize; continue; } errstr = squotef(_("creating chunk holding file \"%s\": %s"), tmp_filename, strerror(errno)); aclose(db->fd); rc = 0; goto common_exit; } save_type = file.type; file.type = F_CONT_DUMPFILE; file.cont_filename[0] = '\0'; if(write_tapeheader(newfd, &file)) { int save_errno = errno; aclose(newfd); if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); db->use = (off_t)0; /* force RQ_MORE DISK */ db->split_size = dumpsize; continue; } errstr = squotef(_("write_tapeheader file %s: %s"), tmp_filename, strerror(errno)); rc = 0; goto common_exit; } /* * Now, update the header of the current file to point * to the next chunk, and then close it. */ if (lseek(db->fd, (off_t)0, SEEK_SET) < (off_t)0) { errstr = squotef(_("lseek holding file %s: %s"), db->filename, strerror(errno)); aclose(newfd); rc = 0; goto common_exit; } file.type = save_type; strncpy(file.cont_filename, new_filename, SIZEOF(file.cont_filename)); file.cont_filename[SIZEOF(file.cont_filename)] = '\0'; if(write_tapeheader(db->fd, &file)) { errstr = squotef(_("write_tapeheader file \"%s\": %s"), db->filename, strerror(errno)); aclose(newfd); unlink(tmp_filename); rc = 0; goto common_exit; } file.type = F_CONT_DUMPFILE; /* * Now shift the file descriptor. */ aclose(db->fd); db->fd = newfd; newfd = -1; /* * Update when we need to chunk again */ if(db->use <= (off_t)DISK_BLOCK_KB) { /* * Cheat and use one more block than allowed so we can make * some progress. */ db->split_size += (off_t)(2 * DISK_BLOCK_KB); db->use = (off_t)0; } else if(db->chunk_size > db->use) { db->split_size += db->use; db->use = (off_t)0; } else { db->split_size += db->chunk_size; db->use -= db->chunk_size; } amfree(tmp_filename); amfree(new_filename); dumpsize += (off_t)DISK_BLOCK_KB; filesize = (off_t)DISK_BLOCK_KB; headersize += DISK_BLOCK_KB; db->filename_seq++; } /* * Write out the buffer */ written = fullwrite(db->fd, db->dataout, (size_t)(db->datain - db->dataout)); if (written > 0) { db->dataout += written; dumpbytes += (off_t)written; } dumpsize += (dumpbytes / (off_t)1024); filesize += (dumpbytes / (off_t)1024); dumpbytes %= 1024; if (written < 0) { if (errno != ENOSPC) { errstr = squotef(_("data write: %s"), strerror(errno)); rc = 0; goto common_exit; } /* * NO-ROOM is informational only. Later, RQ_MORE_DISK will be * issued to use another holding disk. */ putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); db->use = (off_t)0; /* force RQ_MORE_DISK */ db->split_size = dumpsize; goto common_exit; } if (db->datain == db->dataout) { /* * We flushed the whole buffer so reset to use it all. */ db->datain = db->dataout = db->buf; }common_exit: amfree(new_filename); /*@i@*/ amfree(tmp_filename); amfree(arg_filename); amfree(qarg_filename); return rc;}/* * Send an Amanda dump header to the output file and set file->blocksize */static ssize_twrite_tapeheader( int outfd, dumpfile_t *file){ char *buffer; ssize_t written; file->blocksize = DISK_BLOCK_BYTES; buffer = build_header(file, DISK_BLOCK_BYTES); written = fullwrite(outfd, buffer, DISK_BLOCK_BYTES); amfree(buffer); if(written == DISK_BLOCK_BYTES) return 0; if(written < 0) return written; errno = ENOSPC; return (ssize_t)-1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -