linux-sysprog · intermediate · ~20 min

Join two path components safely

snprintf-based safe concatenation with the per-segment slash rule.

Challenge

Join two path components into dir/file form with exactly one separator — no missing slash, no doubled slash — bounded by the output buffer size.

Task

Implement int path_join(char *out, size_t cap, const char *a, const char *b) that combines a and b into out.

Input

  • out, cap: destination buffer and its size.
  • a, b: the two path components.

Output

Builds the joined path in out and returns 0, or returns -1 if it would not fit in cap. The join rules, in order:

  • if b starts with / (absolute), out is just b;
  • else if a is empty, out is just b;
  • else if b is empty, out is just a;
  • otherwise out is a + b with exactly one / between them (don't add a slash if a already ends with one).

Example

path_join(out, 32, "/etc",  "passwd")   ->   0, out = "/etc/passwd"
path_join(out, 32, "/etc/", "passwd")   ->   0, out = "/etc/passwd"   (no double slash)
path_join(out, 32, "/etc",  "/passwd")  ->   0, out = "/passwd"       (b is absolute)
path_join(out, 32, "",      "passwd")   ->   0, out = "passwd"
path_join(out, 32, "a",     "b")        ->   0, out = "a/b"
path_join(out, 5,  "/etc",  "passwd")   ->   -1                       (too small)

Edge cases

  • b absolute, a empty, or b empty — see the rules above.
  • a already ending in / — only one slash in the result.
  • cap too small for the result: -1.

Rules

  • Use snprintf and treat a truncated result (>= cap) as -1.

Why this matters

Every CLI tool that constructs dir/file does some version of this. Doing it without snprintf overflows or double slashes is the kind of small care that distinguishes solid C from sloppy.

Input format

An output buffer out of size cap, plus two path components a and b.

Output format

Writes the joined path into out and returns 0; returns -1 if it does not fit.

Constraints

Absolute b or empty a copies b; empty b copies a; otherwise join with exactly one '/'. Use snprintf and reject truncation.

Starter code

#include <stddef.h>
int path_join(char *out, size_t cap, const char *a, const char *b) { /* TODO */ return -1; }

Common mistakes

Always inserting / (creates // when a already ends with /). Forgetting the absolute-b rule. Failing to detect snprintf truncation.

Edge cases to handle

Both empty; a ending in /; b starting with /; tiny cap.

Complexity

O(strlen(a) + strlen(b)).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.