I hope this isn't the wrong forum! I'm aware that I'm using some non-ANSI-C functions, but my problem seems to be with simple C strings and pointers, so I'm posting it here.
I wrote a simple program to sort torrent files by tracker. It parses the files for the first http tracker, creates a subdirectory named after the tracker, then moves (renames) the input file into that directory.
The program works in two modes: directory mode, which scans the top level of a directory for torrent files, and file mode, which accepts a list of files in the command line (designed for working with shell globbing).
Everything seemed to be working fine until this morning, when I decided to modify the file mode to work using absolute paths, as well as its previous function of using relative paths.
I immediately noticed that it now worked only on the first iteration: beginning with the second file, it didn't work in absolute path mode. Each time running the program would move one file, and all the others would fail.
I began putting some printf statements in to assist with debugging, and I immediately determined that calling printf() on a string (including a string literal) caused the problem to go away, at least most of the time. Very strange, I thought.
After a little more playing I discovered that, beginning with the second iteration, the string I was using to represent the path of the file to to the final "/" (equivalent to unix dirname) had one or more superfluous characters. Which character (or characters) appear seems to depend on the length of the original filename (or argv), and possibly its content.
Now, I can't think of any reason why a simple printf() call would affect other, unrelated code, unless I have incurred some memory referencing problem. Granted, the print statement doesn't resolve the problem in all instances, but in many cases the program will run to completion on a whole set of torrent files, where it would have failed on the same set of files without that printf() statement.
The program encounters no runtime or compile errors, as I run no checks on the success or failure of rename (on the assumption that, if my code is correct, rename will not ordinarily fail). The files, beginning with the second, simply fail to be moved, as the string used to represent their destination has superfluous characters and thus cannot math the created directory. If using torrent files from more than one tracker, I assume that mkdir would also fail after the first iteration, again without any checks.
I was hoping that someone might be able to take a look at my code and tell me what I'm doing wrong. I've highlighted in red the section of code where the problem occurs.
Incidentally, the commented-out printf() call in the highlighted if-statement is the printf() call which seems to have such a great effect on end result of my string creation.
Code:
int main (int argc, const char * argv[]) {
if (argc <= 1) {
printf("Error: No input file.");
return 1;
}
// check if first char of second arg is "-"
if (argv[1][0] == '-') {
if (strlen(argv[1]) > 2) {
printf("Error: Invalid flag.");
return 1;
}
switch (argv[1][1]) {
case 'd': scanDirectory(argv[2]); return 0;
default: printf("Error: Unrecognized flag."); return 1;
}
}
/* at this point we're in file mode, so we treat each argument as a file in
* a for loop and go from there. */
int j;
for (j = 1; j < argc; j++) {
FILE *fp;
char buffer[kMaxBufferSize];
if ( (fp = fopen(argv[j], "r")) == NULL ) {
printf("Error: File not found: %s\n", argv[j]);
continue;
}
if ( fgets(buffer, kMaxBufferSize, fp) == NULL ) {
if ( feof(fp) )
printf("Error: End of file reached: %s\n", argv[j]);
else
printf("Unknown error occured on file: %s\n", argv[j]);
continue;
}
fclose(fp);
char *trackerName;
if ( (trackerName = parseTracker(buffer)) == NULL) {
printf("HTTP tracker not found in file: %s\n", argv[j]);
free(trackerName);
continue;
}
if ( strrchr(argv[j], '/') != NULL) {
char *baseName = strrchr(argv[j], '/');
//printf("%s\n",baseName);
int pathLen = (strlen(argv[j]) - strlen(baseName));
char dest[strlen(argv[j]) + strlen(trackerName)];
strncpy(dest, argv[j], pathLen);
printf("%s\n", dest);
strncat(dest, "/", 1);
strncat(dest, trackerName, strlen(trackerName));
mkdir(dest, 0764);
strncat(dest, baseName, strlen(baseName));
rename(argv[j], dest);
}
else {
mkdir(trackerName, 0764);
char dest[ (strlen(trackerName)) + (strlen(argv[j])) + 1 ];
strcpy(dest, trackerName);
strncat(dest, "/", 1);
strncat(dest, argv[j], strlen(argv[j]) );
rename(argv[j], dest);
}
// last thing before the loop exits
free(trackerName);
}
return 0;
}