Fossil SCM

Fix the file_simplify_name() utility function so that it works with relative pathnames. Ticket [99caf06e17bed849146]

drh 2011-01-12 16:04 trunk
Commit c637a8ac2d60b94eaff4bad82464f86ba4bcbf6a
1 file changed +64 -6
+64 -6
--- src/file.c
+++ src/file.c
@@ -229,48 +229,106 @@
229229
}
230230
}
231231
if( z[i-1]=='/' ) return 0;
232232
return 1;
233233
}
234
+
235
+/*
236
+** If the last component of the pathname in z[0]..z[j-1] is something
237
+** other than ".." then back it out and return true. If the last
238
+** component is empty or if it is ".." then return false.
239
+*/
240
+static int backup_dir(const char *z, int *pJ){
241
+ int j = *pJ;
242
+ int i;
243
+ if( j<=0 ) return 0;
244
+ for(i=j-1; i>0 && z[i-1]!='/'; i--){}
245
+ if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
246
+ *pJ = i-1;
247
+ return 1;
248
+}
234249
235250
/*
236251
** Simplify a filename by
237252
**
253
+** * Convert all \ into / on windows
238254
** * removing any trailing and duplicate /
239255
** * removing /./
240256
** * removing /A/../
241257
**
242258
** Changes are made in-place. Return the new name length.
243259
*/
244260
int file_simplify_name(char *z, int n){
245261
int i, j;
246262
if( n<0 ) n = strlen(z);
263
+
264
+ /* On windows convert all \ characters to / */
247265
#if defined(_WIN32)
248266
for(i=0; i<n; i++){
249267
if( z[i]=='\\' ) z[i] = '/';
250268
}
251269
#endif
270
+
271
+ /* Removing trailing "/" characters */
252272
while( n>1 && z[n-1]=='/' ){ n--; }
273
+
274
+ /* Remove duplicate '/' characters */
253275
for(i=j=0; i<n; i++){
276
+ z[j++] = z[i];
277
+ while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
278
+ }
279
+ n = j;
280
+
281
+ /* Skip over zero or more initial "./" sequences */
282
+ for(i=0; i<n-1 && z[i]=='.' && z[i+1]=='/'; i+=2){}
283
+
284
+ /* Begin copying from z[i] back to z[j]... */
285
+ for(j=0; i<n; i++){
254286
if( z[i]=='/' ){
255
- if( z[i+1]=='/' ) continue;
287
+ /* Skip over internal "/." directory components */
256288
if( z[i+1]=='.' && (i+2==n || z[i+2]=='/') ){
257289
i += 1;
258290
continue;
259291
}
260
- if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/') ){
261
- while( j>0 && z[j-1]!='/' ){ j--; }
262
- if( j>0 ){ j--; }
292
+
293
+ /* If this is a "/.." directory component then back out the
294
+ ** previous term of the directory if it is something other than ".."
295
+ ** or "."
296
+ */
297
+ if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/')
298
+ && backup_dir(z, &j)
299
+ ){
263300
i += 2;
264301
continue;
265302
}
266303
}
267
- z[j++] = z[i];
304
+ if( j>=0 ) z[j] = z[i];
305
+ j++;
268306
}
307
+ if( j==0 ) z[j++] = '.';
269308
z[j] = 0;
270309
return j;
271310
}
311
+
312
+/*
313
+** COMMAND: test-simplify-name
314
+**
315
+** %fossil test-simplify-name FILENAME...
316
+**
317
+** Print the simplified versions of each FILENAME.
318
+*/
319
+void cmd_test_simplify_name(void){
320
+ int i;
321
+ char *z;
322
+ for(i=2; i<g.argc; i++){
323
+ z = mprintf("%s", g.argv[i]);
324
+ printf("[%s] -> ", z);
325
+ file_simplify_name(z, -1);
326
+ printf("[%s]\n", z);
327
+ fossil_free(z);
328
+ }
329
+}
272330
273331
/*
274332
** Compute a canonical pathname for a file or directory.
275333
** Make the name absolute if it is relative.
276334
** Remove redundant / characters
@@ -312,11 +370,11 @@
312370
blob_zero(&x);
313371
for(i=2; i<g.argc; i++){
314372
char zBuf[100];
315373
const char *zName = g.argv[i];
316374
file_canonical_name(zName, &x);
317
- printf("%s\n", blob_buffer(&x));
375
+ printf("[%s] -> [%s]\n", zName, blob_buffer(&x));
318376
blob_reset(&x);
319377
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName));
320378
printf(" file_size = %s\n", zBuf);
321379
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName));
322380
printf(" file_mtime = %s\n", zBuf);
323381
--- src/file.c
+++ src/file.c
@@ -229,48 +229,106 @@
229 }
230 }
231 if( z[i-1]=='/' ) return 0;
232 return 1;
233 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
235 /*
236 ** Simplify a filename by
237 **
 
238 ** * removing any trailing and duplicate /
239 ** * removing /./
240 ** * removing /A/../
241 **
242 ** Changes are made in-place. Return the new name length.
243 */
244 int file_simplify_name(char *z, int n){
245 int i, j;
246 if( n<0 ) n = strlen(z);
 
 
247 #if defined(_WIN32)
248 for(i=0; i<n; i++){
249 if( z[i]=='\\' ) z[i] = '/';
250 }
251 #endif
 
 
252 while( n>1 && z[n-1]=='/' ){ n--; }
 
 
253 for(i=j=0; i<n; i++){
 
 
 
 
 
 
 
 
 
 
254 if( z[i]=='/' ){
255 if( z[i+1]=='/' ) continue;
256 if( z[i+1]=='.' && (i+2==n || z[i+2]=='/') ){
257 i += 1;
258 continue;
259 }
260 if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/') ){
261 while( j>0 && z[j-1]!='/' ){ j--; }
262 if( j>0 ){ j--; }
 
 
 
 
 
263 i += 2;
264 continue;
265 }
266 }
267 z[j++] = z[i];
 
268 }
 
269 z[j] = 0;
270 return j;
271 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
273 /*
274 ** Compute a canonical pathname for a file or directory.
275 ** Make the name absolute if it is relative.
276 ** Remove redundant / characters
@@ -312,11 +370,11 @@
312 blob_zero(&x);
313 for(i=2; i<g.argc; i++){
314 char zBuf[100];
315 const char *zName = g.argv[i];
316 file_canonical_name(zName, &x);
317 printf("%s\n", blob_buffer(&x));
318 blob_reset(&x);
319 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName));
320 printf(" file_size = %s\n", zBuf);
321 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName));
322 printf(" file_mtime = %s\n", zBuf);
323
--- src/file.c
+++ src/file.c
@@ -229,48 +229,106 @@
229 }
230 }
231 if( z[i-1]=='/' ) return 0;
232 return 1;
233 }
234
235 /*
236 ** If the last component of the pathname in z[0]..z[j-1] is something
237 ** other than ".." then back it out and return true. If the last
238 ** component is empty or if it is ".." then return false.
239 */
240 static int backup_dir(const char *z, int *pJ){
241 int j = *pJ;
242 int i;
243 if( j<=0 ) return 0;
244 for(i=j-1; i>0 && z[i-1]!='/'; i--){}
245 if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
246 *pJ = i-1;
247 return 1;
248 }
249
250 /*
251 ** Simplify a filename by
252 **
253 ** * Convert all \ into / on windows
254 ** * removing any trailing and duplicate /
255 ** * removing /./
256 ** * removing /A/../
257 **
258 ** Changes are made in-place. Return the new name length.
259 */
260 int file_simplify_name(char *z, int n){
261 int i, j;
262 if( n<0 ) n = strlen(z);
263
264 /* On windows convert all \ characters to / */
265 #if defined(_WIN32)
266 for(i=0; i<n; i++){
267 if( z[i]=='\\' ) z[i] = '/';
268 }
269 #endif
270
271 /* Removing trailing "/" characters */
272 while( n>1 && z[n-1]=='/' ){ n--; }
273
274 /* Remove duplicate '/' characters */
275 for(i=j=0; i<n; i++){
276 z[j++] = z[i];
277 while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
278 }
279 n = j;
280
281 /* Skip over zero or more initial "./" sequences */
282 for(i=0; i<n-1 && z[i]=='.' && z[i+1]=='/'; i+=2){}
283
284 /* Begin copying from z[i] back to z[j]... */
285 for(j=0; i<n; i++){
286 if( z[i]=='/' ){
287 /* Skip over internal "/." directory components */
288 if( z[i+1]=='.' && (i+2==n || z[i+2]=='/') ){
289 i += 1;
290 continue;
291 }
292
293 /* If this is a "/.." directory component then back out the
294 ** previous term of the directory if it is something other than ".."
295 ** or "."
296 */
297 if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/')
298 && backup_dir(z, &j)
299 ){
300 i += 2;
301 continue;
302 }
303 }
304 if( j>=0 ) z[j] = z[i];
305 j++;
306 }
307 if( j==0 ) z[j++] = '.';
308 z[j] = 0;
309 return j;
310 }
311
312 /*
313 ** COMMAND: test-simplify-name
314 **
315 ** %fossil test-simplify-name FILENAME...
316 **
317 ** Print the simplified versions of each FILENAME.
318 */
319 void cmd_test_simplify_name(void){
320 int i;
321 char *z;
322 for(i=2; i<g.argc; i++){
323 z = mprintf("%s", g.argv[i]);
324 printf("[%s] -> ", z);
325 file_simplify_name(z, -1);
326 printf("[%s]\n", z);
327 fossil_free(z);
328 }
329 }
330
331 /*
332 ** Compute a canonical pathname for a file or directory.
333 ** Make the name absolute if it is relative.
334 ** Remove redundant / characters
@@ -312,11 +370,11 @@
370 blob_zero(&x);
371 for(i=2; i<g.argc; i++){
372 char zBuf[100];
373 const char *zName = g.argv[i];
374 file_canonical_name(zName, &x);
375 printf("[%s] -> [%s]\n", zName, blob_buffer(&x));
376 blob_reset(&x);
377 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName));
378 printf(" file_size = %s\n", zBuf);
379 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName));
380 printf(" file_mtime = %s\n", zBuf);
381

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button