0

Within a C project, I'm trying to make a directory within a specific directory.

// Find the user's home directory.
// Code from https://stackoverflow.com/a/2910392/14602523
struct passwd * pw = getpwuid(getuid());
char * home = pw->pw_dir;

// Test if the ".junk" directory exists in the home directory.
// If not, create it.
if (opendir(strcat(home, "/.junk/")) == NULL) {
    printf(" - no junk directory\n");
    if (mkdir(strcat(home, "/.junk/"), 0777) < 0) {
        fprintf(stderr, "Error: Cannot create junk directory.\n");
        perror(" - errno");
        exit(1);
    }
}

opendir() works correctly: If a directory named .junk/ exists in ~/, then I don't get any print messages, and if the directory doesn't exist then I get some output. But the mkdir() is being really finnicky and causing lots of issues. If ~/.junk/ doesn't exist then I get this output:

 - no junk directory
Error: Cannot create junk directory.
 - errno: No such file or directory

But if I try to make the directory in the current one, such as mkdir("./.junk/", 0777), the directory is created correctly. What's going on? Why does it act differently in ~/ and how can I get it to work?

  • Your first `strcat` uses `".junk"`, but the `mkdir` uses "/.junk/"``. None of your errors says `Cannot empty junk directory`. So your output doesn't match your code. – root Nov 11 '20 at 09:13
  • @DavidCullen No, I was able to find the folder correctly using `getpwuid()` and that part works with `opendir()`. But for some reason it doesn't work with `mkdir()`. – Zach Attack Nov 11 '20 at 22:39
  • @root Whoops, those are my fault. I was trying different formatting to see if it makes a difference and I forgot to copy the most recent one. Also the "empty" error was from a different part of the code so that's not important. Edited the question to fix those. But I still can't figure out why `opendir()` can access the folder but `mkdir()` can't. – Zach Attack Nov 11 '20 at 22:43
  • This is unrelated to your problem, but don't use `pw->pw_dir` do get the current home dir. `pw->pw_dir` is supposed to be the initial home directory when logging in. The user may want to change the current directory when running your program, so you should use `getenv("HOME")` rather than `pw->pw_dir`. See `man getpwuid` for details. – HAL9000 Nov 11 '20 at 22:56
  • @HAL9000 Good to know, I changed that. Thanks! – Zach Attack Nov 12 '20 at 00:43

2 Answers2

2

You have home set to pw->pw_dir, which is defined as type char *, and you're trying to append to it. There's no guarantee that what pw->pw_dir points to has enough space to append additional characters. There's a good chance you're writing past the end of a buffer.

Even if you're not overwriting a buffer, you're appending "/.junk" twice, so the string you pass to mkdir is "home/.junk//.junk"

You need to create a separate string for the full directory name that's big enough to hold it and build it there.

struct passwd * pw = getpwuid(getuid());
char * home = pw->pw_dir;
char junk_dir[strlen(pw->pw_dir) + strlen("/.junk/") + 1];
sprintf(junk_dir, "%s/.junk/", home);

// Test if the ".junk" directory exists in the home directory.
// If not, create it.
if (opendir(junk_dir) == NULL) {
    printf(" - no junk directory\n");
    if (mkdir(junk_dir), 0777) < 0) {
        fprintf(stderr, "Error: Cannot create junk directory.\n");
        perror(" - errno");
        exit(1);
    }
}
dbush
  • 205,898
  • 23
  • 218
  • 273
2
  1. strcat appends to the string in place. The string returned from getpwuid is not meant to be written at all.

  2. It certainly isn't guaranteed to have any usable space after it, so you can't safely append to it.

  3. And even if you could, you call strcat twice, so the string passed to mkdir is something like /home/zach/.junk//.junk/, which will fail as you're trying to create a directory in /home/zach/.junk which you've just determined didn't exist.

This code is written as if you're thinking that strings are "first class" objects in C, that can be manipulated purely as values like in many other languages. Well, they're not - they're arrays of characters, and as with all other arrays, the memory management is up to you.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • The `strcat()` was the problem. I keep forgetting how to use the `` functions... I changed the code and it works now. Thank you so much! Also, someone else mentioned that I shouldn't use `getpwuid()` and I changed that as well. – Zach Attack Nov 12 '20 at 00:46