char curr_dir[MAXPATHLEN];
+unsigned int curr_dir_len;
/**
- * Like chdir() but can be reversed with pop_dir() if @p save is set.
- * It is also much faster as it remembers where we have been.
+ * Like chdir(), but it keeps track of the current directory (in the
+ * global "curr_dir"), and ensures that the path size doesn't overflow.
+ * Also cleans the path using the clean_fname() function.
**/
-char *push_dir(char *dir, int save)
+int push_dir(char *dir)
{
- char *ret = curr_dir;
static int initialised;
+ unsigned int len;
if (!initialised) {
initialised = 1;
getcwd(curr_dir, sizeof(curr_dir)-1);
+ curr_dir_len = strlen(curr_dir);
}
- if (!dir) return NULL; /* this call was probably just to initialize */
+ if (!dir) /* this call was probably just to initialize */
+ return 0;
- if (chdir(dir)) return NULL;
+ len = strlen(dir);
+ if (len == 1 && *dir == '.')
+ return 1;
- if (save) {
- ret = strdup(curr_dir);
- }
+ if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
+ return 0;
+
+ if (chdir(dir))
+ return 0;
if (*dir == '/') {
- strlcpy(curr_dir, dir, sizeof(curr_dir));
- } else if (dir[0] != '.' || dir[1] != '\0') {
- strlcat(curr_dir,"/", sizeof(curr_dir));
- strlcat(curr_dir,dir, sizeof(curr_dir));
+ memcpy(curr_dir, dir, len + 1);
+ curr_dir_len = len;
+ } else {
+ curr_dir[curr_dir_len++] = '/';
+ memcpy(curr_dir + curr_dir_len, dir, len + 1);
+ curr_dir_len += len;
}
clean_fname(curr_dir);
- return ret;
+ return 1;
}
-/** Reverse a push_dir() call */
+/**
+ * Reverse a push_dir() call. You must pass in an absolute path
+ * that was copied from a prior value of "curr_dir".
+ **/
int pop_dir(char *dir)
{
- int ret;
-
- ret = chdir(dir);
- if (ret) {
- free(dir);
- return ret;
- }
-
- strlcpy(curr_dir, dir, sizeof(curr_dir));
+ if (chdir(dir))
+ return 0;
- free(dir);
+ curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
+ if (curr_dir_len >= sizeof curr_dir)
+ curr_dir_len = sizeof curr_dir - 1;
- return 0;
+ return 1;
}
/**