summaryrefslogtreecommitdiff
blob: b8b2a7e11ff8da89c5bb47bcdc0f3b28e7dfc7a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
diff -ur nano-1.3.12/src/files.c nano-1.3.12-fixed/src/files.c
--- nano-1.3.12/src/files.c	2006-06-14 09:19:43.000000000 -0400
+++ nano-1.3.12-fixed/src/files.c	2006-07-05 11:44:17.000000000 -0400
@@ -902,21 +902,29 @@
  * able to go there. */
 char *get_full_path(const char *origpath)
 {
-    char *d_here, *d_there = NULL;
+    struct stat fileinfo;
+    char *d_here, *d_there, *d_there_file = NULL;
+    const char *last_slash;
+    bool path_only;
 
     if (origpath == NULL)
     	return NULL;
 
-    /* Get the current directory. */
+    /* Get the current directory.  If it doesn't exist, back up and try
+     * again until we get a directory that does, and use that as the
+     * current directory. */
     d_here = charalloc(PATH_MAX + 1);
     d_here = getcwd(d_here, PATH_MAX + 1);
 
-    if (d_here != NULL) {
-	const char *last_slash;
-	char *d_there_file = NULL;
-	bool path_only;
-	struct stat fileinfo;
+    while (d_here == NULL) {
+	if (chdir("..") == -1)
+	    break;
+
+	d_here = getcwd(d_here, PATH_MAX + 1);
+    }
 
+    /* If we succeeded, canonicalize it in d_here. */
+    if (d_here != NULL) {
 	align(&d_here);
 
 	/* If the current directory isn't "/", tack a slash onto the end
@@ -925,89 +933,91 @@
 	    d_here = charealloc(d_here, strlen(d_here) + 2);
 	    strcat(d_here, "/");
 	}
+    /* Otherwise, set d_here to "". */
+    } else
+	d_here = mallocstrcpy(NULL, "");
 
-	d_there = real_dir_from_tilde(origpath);
+    d_there = real_dir_from_tilde(origpath);
 
-	assert(d_there != NULL);
+    assert(d_there != NULL);
 
-	/* Stat d_there.  If stat() fails, assume that d_there refers to
-	 * a new file that hasn't been saved to disk yet.  Set path_only
-	 * to TRUE if d_there refers to a directory, and FALSE if
-	 * d_there refers to a file. */
-	path_only = !stat(d_there, &fileinfo) &&
-		S_ISDIR(fileinfo.st_mode);
-
-	/* If path_only is TRUE, make sure d_there ends in a slash. */
-	if (path_only) {
-	    size_t d_there_len = strlen(d_there);
-
-	    if (d_there[d_there_len - 1] != '/') {
-		d_there = charealloc(d_there, d_there_len + 2);
-		strcat(d_there, "/");
-	    }
-	}
+    /* If stat()ing d_there fails, assume that d_there refers to a new
+     * file that hasn't been saved to disk yet.  Set path_only to TRUE
+     * if d_there refers to a directory, and FALSE otherwise. */
+    path_only = stat(d_there, &fileinfo) == 0 &&
+	S_ISDIR(fileinfo.st_mode);
 
-	/* Search for the last slash in d_there. */
-	last_slash = strrchr(d_there, '/');
+    /* If path_only is TRUE, make sure d_there ends in a slash. */
+    if (path_only) {
+	size_t d_there_len = strlen(d_there);
 
-	/* If we didn't find one, then make sure the answer is in the
-	 * format "d_here/d_there". */
-	if (last_slash == NULL) {
-	    assert(!path_only);
+	if (d_there[d_there_len - 1] != '/') {
+	    d_there = charealloc(d_there, d_there_len + 2);
+	    strcat(d_there, "/");
+	}
+    }
 
-	    d_there_file = d_there;
-	    d_there = d_here;
-	} else {
-	    /* If path_only is FALSE, then save the filename portion of
-	     * the answer, everything after the last slash, in
-	     * d_there_file. */
-	    if (!path_only)
-		d_there_file = mallocstrcpy(NULL, last_slash + 1);
-
-	    /* And remove the filename portion of the answer from
-	     * d_there. */
-	    null_at(&d_there, last_slash - d_there + 1);
-
-	    /* Go to the path specified in d_there. */
-	    if (chdir(d_there) == -1) {
-		free(d_there);
-		d_there = NULL;
-	    } else {
-		/* Get the full path and save it in d_there. */
-		free(d_there);
+    /* Search for the last slash in d_there. */
+    last_slash = strrchr(d_there, '/');
 
-		d_there = charalloc(PATH_MAX + 1);
-		d_there = getcwd(d_there, PATH_MAX + 1);
+    /* If we didn't find one, then make sure the answer is in the format
+     * "d_here/d_there". */
+    if (last_slash == NULL) {
+	assert(!path_only);
 
-		if (d_there != NULL) {
-		    align(&d_there);
+	d_there_file = d_there;
+	d_there = d_here;
+    } else {
+	/* If path_only is FALSE, then save the filename portion of the
+	 * answer (everything after the last slash) in d_there_file. */
+	if (!path_only)
+	    d_there_file = mallocstrcpy(NULL, last_slash + 1);
+
+	/* And remove the filename portion of the answer from
+	 * d_there. */
+	null_at(&d_there, last_slash - d_there + 1);
+
+	/* Go to the path specified in d_there. */
+	if (chdir(d_there) == -1) {
+	    free(d_there);
+	    d_there = NULL;
+	} else {
+	    free(d_there);
 
-		    if (strcmp(d_there, "/") != 0) {
-			/* Make sure d_there ends in a slash. */
-			d_there = charealloc(d_there,
-				strlen(d_there) + 2);
-			strcat(d_there, "/");
-		    }
-		} else
-		    /* If we couldn't get the full path, set path_only
-		     * to TRUE so that we clean up correctly, free all
-		     * allocated memory, and return NULL. */
-		    path_only = TRUE;
-
-		/* Finally, go back to the path specified in d_here,
-		 * where we were before. */
-		chdir(d_here);
-	    }
+	    /* Get the full path. */
+	    d_there = charalloc(PATH_MAX + 1);
+	    d_there = getcwd(d_there, PATH_MAX + 1);
+
+	    /* If we succeeded, canonicalize it in d_there. */
+	    if (d_there != NULL) {
+		align(&d_there);
+
+		/* If the current directory isn't "/", tack a slash onto
+		 * the end of it. */
+		if (strcmp(d_there, "/") != 0) {
+		    d_there = charealloc(d_there, strlen(d_there) + 2);
+		    strcat(d_there, "/");
+		}
+	    } else
+		/* Otherwise, set path_only to TRUE, so that we clean up
+		 * correctly, free all allocated memory, and return
+		 * NULL. */
+		path_only = TRUE;
+
+	    /* Finally, go back to the path specified in d_here,
+	     * where we were before.  We don't check for a chdir()
+	     * error, since we can do nothing then. */
+	    chdir(d_here);
 
 	    /* Free d_here, since we're done using it. */
 	    free(d_here);
 	}
 
-	/* At this point, if path_only is FALSE and d_there exists,
+	/* At this point, if path_only is FALSE and d_there isn't NULL,
 	 * d_there contains the path portion of the answer and
 	 * d_there_file contains the filename portion of the answer.  If
-	 * this is the case, tack d_there_file onto the end of
-	 * d_there, so that d_there contains the complete answer. */
+	 * this is the case, tack the latter onto the end of the former.
+	 * d_there will then contain the complete answer. */
 	if (!path_only && d_there != NULL) {
 	    d_there = charealloc(d_there, strlen(d_there) +
 		strlen(d_there_file) + 1);