void TestReportHistory::test_reduce_path() { #if !DISABLE_ALL || 0 QStringList input{ // {"test1/a/b/c/d.json/report/data/sn"}, // {"test1/a/b/c/e.json/report/data/sn"}, {"test1/a/b/c/e.json/report/data/datetime"}, {"test1/a/b/c/e.json/report/data/today"}, {"test1/a/b/c/e.json/report/data2/today"}, {"test1/a/b/c/e.json/report/data/equal/string"}, {"test1/a/b/c/e.json/report/data/equal/string"} // }; QStringList output_wanted{ // {"d.json/report/data/sn"}, // {"e.json/report/data/sn"}, {"datetime"}, {"data/today"}, {"data2/today"}, {"test1/a/b/c/e.json/report/data/equal/string"}, {"test1/a/b/c/e.json/report/data/equal/string"} // }; auto output = reduce_path(input); int i = 0; for (auto &out_s : output) { QCOMPARE(out_s, output_wanted[i]); i++; } #endif }
/* * WRQ - receive a file from the client */ void tftp_wrq(int peer, char *recvbuffer, ssize_t size) { char *cp; int has_options = 0, ecode; char *filename, *mode; char fnbuf[PATH_MAX]; cp = parse_header(peer, recvbuffer, size, &filename, &mode); size -= (cp - recvbuffer) + 1; strlcpy(fnbuf, filename, sizeof(fnbuf)); reduce_path(fnbuf); filename = fnbuf; if (size > 0) { if (options_rfc_enabled) has_options = !parse_options(peer, cp, size); else tftp_log(LOG_INFO, "Options found but not enabled"); } ecode = validate_access(peer, &filename, WRQ); if (ecode == 0) { if (has_options) send_oack(peer); else send_ack(peer, 0); } if (logging) { tftp_log(LOG_INFO, "%s: write request for %s: %s", peername, filename, errtomsg(ecode)); } if (ecode) { send_error(peer, ecode); exit(1); } tftp_recvfile(peer, mode); exit(0); }
int main(int argc, char **argv) { // Misc temporary variables int i, j, k, l, ch, want_by_default, should_do, new_number, empty, temp_int; off_t offset,con_len; time_t rawtime; struct tm *ptm; char *temp_str = NULL; char *temp_str2 = NULL; char *tok_str = NULL; int steps = 6; int cur_step = 1; int delete_needed = 0; int to_file = 1; // Variables to help analyze user input int in = 0; int out = 0; int incl = 0; int excl = 0; int drop = 0; int redef = 0; // Variables related to files and paths FILE *infile = NULL; FILE *outfile = NULL; FILE *messages = stdout; char **include = NULL; // Holds the paths the user wants to keep char **exclude = NULL; // Holds the paths the user wants to discard char **mustkeep = NULL; // For storing the paths the user wants to discard, but must be kept char **relevant_paths = NULL; char **no_longer_relevant = NULL; char *redefined_root = NULL; // Variables to hold the size of 2D pseudoarrays int inc_len = 0; int exc_len = 0; int must_len = 0; int rel_len = 0; int no_len = 0; int cur_len = 0; int cur_max = 80; // File reading & writing variables char *current_line; if ((current_line = (char*)calloc(cur_max, 1)) == NULL) { exit_with_error("calloc failed", 2); } int reading_node = 0; int writing = 1; int toggle = 0; // Variables related to revisions and nodes int drop_empty = 0; int rev_len = -1; int rev_max = 10; int rev = -1; revision *revisions; if ((revisions = (revision*)malloc(rev_max * sizeof(revision))) == NULL) { exit_with_error("malloc failed", 2); } int nod_len = -1; int nod = -1; node *current_node = NULL; // Analyze the given parameters for (i = 1 ; i < argc ; ++i) { if (starts_with(argv[i], "-")) { if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { free(current_line); free(revisions); free(include); free(exclude); show_help_and_exit(); } in = (!strcmp(argv[i], "--infile") || !strcmp(argv[i], "-i")); out = (!strcmp(argv[i], "--outfile") || !strcmp(argv[i], "-o")); incl = (!strcmp(argv[i], "--include") || !strcmp(argv[i], "-n")); excl = (!strcmp(argv[i], "--exclude") || !strcmp(argv[i], "-e")); drop = (!strcmp(argv[i], "--drop-empty") || !strcmp(argv[i], "-d")); redef = (!strcmp(argv[i], "--redefine-root") || !strcmp(argv[i], "-r")); if (!(in || out || incl || excl || drop || redef)) { exit_with_error(strcat(argv[i], " is not a valid parameter. Use -h for help."), 1); } else if (drop) { drop_empty = 1; steps = 7; } } else if (in && infile == NULL) { infile = fopen(argv[i],"rb"); if (infile == NULL) { exit_with_error(strcat(argv[i], " can not be opened as infile") , 3); } } else if (out && outfile == NULL) { outfile = fopen(argv[i],"wb"); if (outfile == NULL) { exit_with_error(strcat(argv[i], " can not be opened as outfile") , 3); } } else if (incl) { if ((include = (char**)realloc(include, (inc_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } // Allow the user to escape a directory in the repository root, that starts with a // hyphen, using a slash. if (starts_with(argv[i], "/")) { include[inc_len] = &argv[i][1]; } else { include[inc_len] = argv[i]; } ++inc_len; } else if (excl) { if ((exclude = (char**)realloc(exclude, (exc_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } if (starts_with(argv[i], "/")) { exclude[exc_len] = &argv[i][1]; } else { exclude[exc_len] = argv[i]; } ++exc_len; } else if (redef && redefined_root == NULL) { redefined_root = argv[i]; } else { exit_with_error(strcat(argv[i], " is not a valid parameter. Use -h for help."), 1); } } if (infile == NULL) { exit_with_error("You must specify an infile", 1); } if (outfile == NULL) { to_file = 0; outfile = stdout; messages = stderr; } if (include == NULL && exclude == NULL) { fclose(infile); if (to_file) { fclose(outfile); } exit_with_error("You must specify something to either include or exclude", 1); } if (include != NULL && exclude != NULL) { fclose(infile); if (to_file) { fclose(outfile); } exit_with_error("You may not specify both includes and excludes", 1); } if (exclude != NULL && redefined_root != NULL) { fclose(infile); if (to_file) { fclose(outfile); } exit_with_error("You may not redefine root when using excludes", 1); } if (redefined_root != NULL) { temp_str = str_malloc(strlen(redefined_root) + 2); strcpy(temp_str, redefined_root); strcat(temp_str, "/"); for (i = 0; i < inc_len; ++i) { if (!(strcmp(include[i], redefined_root) == 0 || starts_with(include[i], temp_str))) { fclose(infile); if (outfile != NULL) { fclose(outfile); } strcat(redefined_root, " can not be redefined as root for include "); exit_with_error(strcat(redefined_root, include[i]), 1); } } free(temp_str); } want_by_default = (include == NULL); fprintf(messages, "Step %d/%d: Reading the infile... ", cur_step, steps); fflush(messages); ++cur_step; // Read the metadata from all nodes. while ((ch = fgetc(infile)) != EOF) { // Once we reach a newline character we need to analyze the data. if (ch == NEWLINE) { // Data inside nodes needs special treatment. if (reading_node) { // An empty line while reading a node, means the node stops here. if (strlen(current_line) == 0) { reading_node = 0; } // A line starting with "Content-lenth: " means that the content // of the node is the only thing left of it. else if (starts_with(current_line,"Content-length: ")) { // The content is irrelevant (and might mess things up). Skip it. fseeko(infile, (off_t)atol(¤t_line[16]) + CONTENT_PADDING, SEEK_CUR); reading_node = 0; } else if (starts_with(current_line,"Node-action: ")) { if (strcmp(¤t_line[13],"add") == 0) { current_node[nod_len].action = ADD; } else if (strcmp(¤t_line[13],"delete") == 0) { current_node[nod_len].action = DELETE; } else if (strcmp(¤t_line[13],"change") == 0) { current_node[nod_len].action = CHANGE; } else { current_node[nod_len].action = REPLACE; } } else if (starts_with(current_line,"Node-copyfrom-path: ")) { current_node[nod_len].copyfrom = str_malloc(strlen(¤t_line[19])); strcpy(current_node[nod_len].copyfrom, ¤t_line[20]); } } // End of "if (reading_node)" else if (starts_with(current_line,"Node-path: ")) { ++nod_len; ++revisions[rev_len].size; if (nod_len == 0) { if ((current_node = (node*)malloc(sizeof(node))) == NULL) { exit_with_error("malloc failed", 2); } } else if ((current_node = (node*)realloc(current_node, (nod_len + 1) * sizeof(node))) == NULL) { exit_with_error("realloc failed", 2); } current_node[nod_len].path = str_malloc(strlen(¤t_line[10])); strcpy(current_node[nod_len].path, ¤t_line[11]); current_node[nod_len].copyfrom = NULL; current_node[nod_len].wanted = want_by_default; reading_node = 1; } else if (starts_with(current_line,"Revision-number: ")) { if (rev_len >= 0) { revisions[rev_len].nodes = current_node; } ++rev_len; if (rev_len == rev_max) { rev_max += INCREMENT; if ((revisions = (revision*)realloc(revisions, (rev_max * sizeof(revision)))) == NULL) { exit_with_error("realloc failed", 2); } } current_node = NULL; revisions[rev_len].nodes = NULL; revisions[rev_len].size = 0; revisions[rev_len].number = -1; nod_len = -1; } current_line[0] = '\0'; cur_len = 0; } // End of "if (ch != NEWLINE)" else { if (cur_len == cur_max - 1) { cur_max += INCREMENT; if ((current_line = (char*)realloc(current_line, cur_max)) == NULL) { exit_with_error("realloc failed", 2); } } current_line[cur_len] = ch; ++cur_len; current_line[cur_len] = '\0'; } } // End of "while ((ch = fgetc(infile)) != EOF)" if (rev_len >= 0) { revisions[rev_len].nodes = current_node; } ++rev_len; current_line[0] = '\0'; cur_len = 0; fprintf(messages, "OK\nStep %d/%d: Removing unwanted nodes... ", cur_step, steps); fflush(messages); ++cur_step; // Analyze the metadata in order to decide which nodes to keep. // If the user specified excludes, mark nodes in the exclude paths as unwanted. // (By default all nodes are wanted when using excludes.) if (exclude != NULL) { for (i = rev_len - 1; i >= 0; --i) { for (j = 0; j < revisions[i].size; ++j) { for (k = 0; k < exc_len; ++k) { temp_str = str_malloc(strlen(exclude[k]) + 2); strcpy(temp_str, exclude[k]); strcat(temp_str, "/"); if (strcmp(revisions[i].nodes[j].path, exclude[k]) == 0 || starts_with(revisions[i].nodes[j].path, temp_str)) { revisions[i].nodes[j].wanted = 0; } free(temp_str); } // Check whether the node has been marked as a "must keep". Keep it if it has. for (k = 0; k < must_len; ++k) { if ((temp_str = (char*)calloc(strlen(mustkeep[k]) + 2, 1)) == NULL) { exit_with_error("calloc failed", 2); } temp_str2 = str_malloc(strlen(mustkeep[k]) + 1); strcpy(temp_str2, mustkeep[k]); tok_str = strtok(temp_str2, "/"); while (tok_str != NULL) { strcat(temp_str,tok_str); if (strcmp(revisions[i].nodes[j].path, temp_str) == 0) { revisions[i].nodes[j].wanted = 1; } strcat(temp_str,"/"); tok_str = strtok(NULL, "/"); } if (starts_with(revisions[i].nodes[j].path, temp_str)) { revisions[i].nodes[j].wanted = 1; } free(temp_str); free(temp_str2); } // Check whether the path should be added as a "must keep". if (revisions[i].nodes[j].wanted && revisions[i].nodes[j].copyfrom != NULL) { should_do = 0; for (k = 0; k < exc_len; ++k) { temp_str = str_malloc(strlen(exclude[k]) + 2); strcpy(temp_str, exclude[k]); strcat(temp_str, "/"); if (strcmp(revisions[i].nodes[j].copyfrom, exclude[k]) == 0 || starts_with(revisions[i].nodes[j].copyfrom, temp_str)) { should_do = 1; } free(temp_str); } if (should_do) { if ((mustkeep = (char**)realloc(mustkeep, (must_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } mustkeep[must_len] = str_malloc(strlen(revisions[i].nodes[j].copyfrom) + 1); strcpy(mustkeep[must_len], revisions[i].nodes[j].copyfrom); ++must_len; } } } } } // If the user specified includes, mark nodes in the include paths as wanted. // (By default all nodes are unwanted when using includes.) else { for (i = rev_len - 1; i >= 0; --i) { for (j = 0 ; j < revisions[i].size ; ++j) { for (k = 0; k < inc_len; ++k) { temp_str = str_malloc(strlen(include[k]) + 2); strcpy(temp_str, include[k]); strcat(temp_str, "/"); temp_str2 = str_malloc(strlen(revisions[i].nodes[j].path) + 2); strcpy(temp_str2, revisions[i].nodes[j].path); strcat(temp_str2, "/"); if (strcmp(revisions[i].nodes[j].path, include[k]) == 0 || starts_with(revisions[i].nodes[j].path, temp_str) || starts_with(include[k], temp_str2)) { revisions[i].nodes[j].wanted = 1; } free(temp_str); free(temp_str2); } // Check whether the node has been marked as a "must keep". for (k = 0; k < must_len; ++k) { if ((temp_str = (char*)calloc(strlen(mustkeep[k]) + 2, 1)) == NULL) { exit_with_error("calloc failed", 2); } temp_str2 = str_malloc(strlen(mustkeep[k]) + 1); strcpy(temp_str2, mustkeep[k]); tok_str = strtok(temp_str2, "/"); while (tok_str != NULL) { strcat(temp_str,tok_str); if (strcmp(revisions[i].nodes[j].path, temp_str) == 0) { revisions[i].nodes[j].wanted = 1; } strcat(temp_str,"/"); tok_str = strtok(NULL, "/"); } if (starts_with(revisions[i].nodes[j].path, temp_str)) { revisions[i].nodes[j].wanted = 1; } free(temp_str); free(temp_str2); } // Check whether the path should be added as a "must keep". if (revisions[i].nodes[j].wanted && revisions[i].nodes[j].copyfrom != NULL) { should_do = 1; for (k = 0; k < inc_len; ++k) { temp_str = str_malloc(strlen(include[k]) + 2); strcpy(temp_str, include[k]); strcat(temp_str, "/"); if (strcmp(revisions[i].nodes[j].copyfrom, include[k]) == 0 || starts_with(revisions[i].nodes[j].copyfrom, temp_str)) { should_do = 0; } free(temp_str); } if (should_do) { if ((mustkeep = (char**)realloc(mustkeep, (must_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } mustkeep[must_len] = str_malloc(strlen(revisions[i].nodes[j].copyfrom) + 1); strcpy(mustkeep[must_len], revisions[i].nodes[j].copyfrom); ++must_len; } } } } } fprintf(messages, "OK\nStep %d/%d: Bringing back necessary delete operations... ", cur_step, steps); fflush(messages); ++cur_step; // Parse through the metadata again - this time bringing back any // possible delete instructions for the nodes we were forced to keep // but actually don't want any more. for (i = 0; i < rev_len; ++i) { for (j = 0; j < revisions[i].size; ++j) { if (revisions[i].nodes[j].wanted && revisions[i].nodes[j].action != DELETE) { should_do = 1; for (k = 0; k < rel_len; ++k) { if (relevant_paths[k] != NULL && strcmp(revisions[i].nodes[j].path, relevant_paths[k]) == 0) { should_do = 0; } } if (should_do) { if ((relevant_paths = (char**)realloc(relevant_paths, (rel_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } relevant_paths[rel_len] = str_malloc(strlen(revisions[i].nodes[j].path) + 1); strcpy(relevant_paths[rel_len], revisions[i].nodes[j].path); ++rel_len; } } if (revisions[i].nodes[j].action == DELETE) { for (k = 0; k < rel_len; ++k) { if (relevant_paths[k] != NULL && strcmp(revisions[i].nodes[j].path, relevant_paths[k]) == 0) { revisions[i].nodes[j].wanted = 1; for (l = 0; l < rel_len; ++l) { temp_str = str_malloc(strlen(revisions[i].nodes[j].path) + 2); strcpy(temp_str, revisions[i].nodes[j].path); strcat(temp_str, "/"); if (relevant_paths[l] != NULL && (strcmp(relevant_paths[l], revisions[i].nodes[j].path) == 0 || starts_with(relevant_paths[l], temp_str))) { free(relevant_paths[l]); relevant_paths[l] = NULL; } free(temp_str); } } } } } } fprintf(messages, "OK\nStep %d/%d: Identifying lingering unwanted nodes... ", cur_step, steps); fflush(messages); ++cur_step; // Find paths which are not relevant as specified by the user, but still lingers // due to dependency includes. (So that we can deal with them later.) for (i = 0; i < rel_len; ++i) { if (include == NULL && relevant_paths[i] != NULL) { for (j = 0; j < exc_len; ++j) { temp_str = str_malloc(strlen(exclude[j]) + 2); strcpy(temp_str, exclude[j]); strcat(temp_str, "/"); if (strcmp(relevant_paths[i], exclude[j]) == 0 || starts_with(relevant_paths[i], temp_str)) { if ((no_longer_relevant = (char**)realloc(no_longer_relevant, (no_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } no_longer_relevant[no_len] = str_malloc(strlen(relevant_paths[i]) + 1); strcpy(no_longer_relevant[no_len], relevant_paths[i]); ++no_len; } free(temp_str); } } else if (exclude == NULL && relevant_paths[i] != NULL) { temp_str = str_malloc(strlen(relevant_paths[i]) + 2); strcpy(temp_str, relevant_paths[i]); strcat(temp_str, "/"); for (j = 0; j < inc_len; ++j) { temp_str2 = str_malloc(strlen(include[j]) + 2); strcpy(temp_str2, include[j]); strcat(temp_str2, "/"); if (!(strcmp(relevant_paths[i], include[j]) == 0 || starts_with(relevant_paths[i], temp_str2) || starts_with(include[j], temp_str))) { if ((no_longer_relevant = (char**)realloc(no_longer_relevant, (no_len + 1) * sizeof(char*))) == NULL) { exit_with_error("realloc failed", 2); } no_longer_relevant[no_len] = str_malloc(strlen(relevant_paths[i]) + 1); strcpy(no_longer_relevant[no_len], relevant_paths[i]); ++no_len; } free(temp_str2); } free(temp_str); } } // Check that we don't have anything specifically included in our "no_longer_relevant"-section. for (i = 0; i < no_len; ++i) { if (no_longer_relevant[i] != NULL) { for (j = 0; j < inc_len ; ++j) { temp_str = str_malloc(strlen(include[j]) + 2); strcpy(temp_str, include[j]); strcat(temp_str, "/"); if (strcmp(no_longer_relevant[i], include[j]) == 0 || starts_with(no_longer_relevant[i], temp_str)) { free(no_longer_relevant[i]); no_longer_relevant[i] = NULL; break; } free(temp_str); } } } // Remove any directory entries that should no longer exist with the redefined root if (redefined_root != NULL) { for (i = 0; i < rev_len ; ++i) { for (j = 0; j < revisions[i].size; ++j) { if (revisions[i].nodes[j].wanted) { temp_str = str_malloc(strlen(redefined_root) + 2); strcpy(temp_str, redefined_root); strcat(temp_str, "/"); for (k = strlen(temp_str) - 1; k > 0; --k) { if (temp_str[k] == '/') { temp_str[k] = '\0'; if (strcmp(temp_str, revisions[i].nodes[j].path) == 0) { revisions[i].nodes[j].wanted = 0; for (l = 0; l < no_len; ++l) { if (strcmp(revisions[i].nodes[j].path, no_longer_relevant[l]) == 0) { free(no_longer_relevant[l]); no_longer_relevant[l] = NULL; } } } } } free(temp_str); } } } // Reduce the paths of deletion candidates, so that we delete the correct paths for (i = 0; i < no_len; ++i) { if (no_longer_relevant[i] != NULL) { temp_str = reduce_path(redefined_root, no_longer_relevant[i]); strcpy(no_longer_relevant[i], temp_str); free(temp_str); } } } // Remove redundant entries (i.e. delete only "trunk" instead of "trunk", "trunk/foo", "trunk/bar", et.c.) for (i = 0; i < no_len; ++i) { if (no_longer_relevant[i] != NULL) { delete_needed = 1; temp_str = str_malloc(strlen(no_longer_relevant[i]) + 2); strcpy(temp_str, no_longer_relevant[i]); strcat(temp_str, "/"); for (j = 0; j < no_len; ++j) { if (i != j && no_longer_relevant[j] != NULL && (starts_with(no_longer_relevant[j], temp_str) || strcmp(no_longer_relevant[i], no_longer_relevant[j]) == 0)) { free(no_longer_relevant[j]); no_longer_relevant[j] = NULL; } } for (j = 0; j < inc_len ; ++j) { if (strcmp(no_longer_relevant[i], include[j]) == 0 || starts_with(include[j], temp_str)) { free(no_longer_relevant[i]); no_longer_relevant[i] = NULL; break; } } free(temp_str); } } // Renumber the revisions if the empty ones are to be dropped if (drop_empty) { fprintf(messages, "OK\nStep %d/%d: Renumbering revisions... ", cur_step, steps); fflush(messages); ++cur_step; revisions[0].number = 0; // Revision 0 is special, and should never be dropped. new_number = 1; for (i = 1; i < rev_len; ++i) { empty = 1; for (j = 0; j < revisions[i].size; ++j) { if (revisions[i].nodes[j].wanted) { empty = 0; break; } } if (!empty) { revisions[i].number = new_number; ++new_number; } } } fprintf(messages, "OK\nStep %d/%d: Writing the outfile... ", cur_step, steps); fflush(messages); ++cur_step; // Copy the infile to the outfile skipping the undesireable parts. reading_node = 0; rewind(infile); while ((ch = fgetc(infile)) != EOF) { if (ch == NEWLINE) { if (reading_node) { if (strlen(current_line) == 0) { reading_node = 0; writing = 1; } else if (drop_empty && writing && starts_with(current_line, "Node-copyfrom-rev: ")) { temp_int = atoi(¤t_line[19]); // It's possible for the copyfrom-rev argument to point to a revision that is being removed. // If this is the case we change it to point to the first revision prior to it, that remains. while (revisions[temp_int].number < 0) { --temp_int; } fprintf(outfile, "Node-copyfrom-rev: %d\n", revisions[temp_int].number); toggle = 1; } else if(writing && redefined_root != NULL && starts_with(current_line, "Node-copyfrom-path: ")) { temp_str = reduce_path(redefined_root, ¤t_line[20]); fprintf(outfile, "Node-copyfrom-path: %s\n", temp_str); toggle = 1; free(temp_str); } else if (starts_with(current_line, "Content-length: ")) { con_len = (off_t)atol(¤t_line[16]); if (writing) { fprintf(outfile, "%s\n", current_line); for (offset = 0; offset < con_len + CONTENT_PADDING; ++offset) { fputc(fgetc(infile), outfile); } } else { fseeko(infile, con_len + CONTENT_PADDING, SEEK_CUR); } reading_node = 0; writing = 1; toggle = 1; } } else if (starts_with(current_line, "Node-path: ")) { reading_node = 1; ++nod; writing = revisions[rev].nodes[nod].wanted; if (writing && redefined_root != NULL) { temp_str = reduce_path(redefined_root, ¤t_line[11]); fprintf(outfile, "Node-path: %s\n", temp_str); toggle = 1; free(temp_str); } } else if (starts_with(current_line, "Revision-number: ")) { ++rev; nod = -1; writing = (!drop_empty || revisions[rev].number >= 0); if (drop_empty && writing) { temp_int = atoi(¤t_line[17]); fprintf(outfile, "Revision-number: %d\n", revisions[temp_int].number); toggle = 1; } } if (writing && !toggle) { fprintf(outfile, "%s\n", current_line); } else { toggle = 0; } current_line[0] = '\0'; cur_len = 0; } else { current_line[cur_len] = ch; ++cur_len; current_line[cur_len] = '\0'; } } fprintf(messages, "OK\nStep %d/%d: Adding revision deleting surplus nodes... ", cur_step, steps); fflush(messages); ++cur_step; // Now we deal with any surplus nodes by adding a revision that deletes them. if (delete_needed) { time(&rawtime); ptm = gmtime(&rawtime); if (drop_empty) { i = 1; do { temp_int = revisions[rev_len - i].number + 1; ++i; } while (temp_int == 0); } else { temp_int = rev_len; } fprintf(outfile, "Revision-number: %d\n", temp_int); fprintf(outfile, "Prop-content-length: 133\n"); fprintf(outfile, "Content-length: 133\n\n"); fprintf(outfile, "K 7\nsvn:log\nV 22\n"); fprintf(outfile, "Deleted unwanted nodes\n"); fprintf(outfile, "K 10\nsvn:author\nV 16\nsvndumpsanitizer\nK 8\nsvn:date\nV 27\n"); fprintf(outfile, "%d-%.2d-%.2dT%.2d:%.2d:%.2d.000000Z\n", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); fprintf(outfile, "PROPS-END\n\n"); for (i = 0; i < no_len; ++i) { if (no_longer_relevant[i] != NULL) { fprintf(outfile, "Node-path: %s\n", no_longer_relevant[i]); fprintf(outfile, "Node-action: delete\n\n\n"); } } fprintf(messages, "OK\n"); } else { fprintf(messages, "NOT NEEDED\n"); } // Clean everything up fclose(infile); if (to_file) { fclose(outfile); } for (i = 0; i < rev_len; ++i) { for (j = 0; j < revisions[i].size; ++j) { free(revisions[i].nodes[j].path); free(revisions[i].nodes[j].copyfrom); } free(revisions[i].nodes); } for (i = 0; i < rel_len; ++i) { free(relevant_paths[i]); } for (i = 0; i < no_len; ++i) { free(no_longer_relevant[i]); } for (i = 0; i < must_len; ++i) { free(mustkeep[i]); } free(revisions); free(relevant_paths); free(no_longer_relevant); free(include); free(exclude); free(mustkeep); free(current_line); return 0; }
/* * RRQ - send a file to the client */ void tftp_rrq(int peer, char *recvbuffer, ssize_t size) { char *cp; int has_options = 0, ecode; char *filename, *mode; char fnbuf[PATH_MAX]; cp = parse_header(peer, recvbuffer, size, &filename, &mode); size -= (cp - recvbuffer) + 1; strcpy(fnbuf, filename); reduce_path(fnbuf); filename = fnbuf; if (size > 0) { if (options_rfc_enabled) has_options = !parse_options(peer, cp, size); else tftp_log(LOG_INFO, "Options found but not enabled"); } ecode = validate_access(peer, &filename, RRQ); if (ecode == 0) { if (has_options) { int n; char lrecvbuffer[MAXPKTSIZE]; struct tftphdr *rp = (struct tftphdr *)lrecvbuffer; send_oack(peer); n = receive_packet(peer, lrecvbuffer, MAXPKTSIZE, NULL, timeoutpacket); if (n < 0) { if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Aborting: %s", rp_strerror(n)); return; } if (rp->th_opcode != ACK) { if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Expected ACK, got %s on OACK", packettype(rp->th_opcode)); return; } } } if (logging) tftp_log(LOG_INFO, "%s: read request for %s: %s", peername, filename, errtomsg(ecode)); if (ecode) { /* * Avoid storms of naks to a RRQ broadcast for a relative * bootfile pathname from a diskless Sun. */ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) exit(0); send_error(peer, ecode); exit(1); } tftp_xmitfile(peer, mode); }