Fossil

Check-in [c637a8ac]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix the file_simplify_name() utility function so that it works with relative pathnames. Ticket [99caf06e17bed849146]
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c637a8ac2d60b94eaff4bad82464f86ba4bcbf6a
User & Date: drh 2011-01-12 16:04:22
Context
2011-01-13
00:01
Add tests for the file_simplify_name utility function. check-in: 6f42e76d user: drh tags: trunk
2011-01-12
16:04
Fix the file_simplify_name() utility function so that it works with relative pathnames. Ticket [99caf06e17bed849146] check-in: c637a8ac user: drh tags: trunk
15:53
Fix for an apparent minor error in allowed markup types for inline text. check-in: dddaebf6 user: lrem tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/file.c.

227
228
229
230
231
232
233















234
235
236
237

238
239
240
241
242
243
244
245
246


247
248
249
250
251


252


253










254
255

256
257
258
259





260
261
262


263
264
265
266
267

268

269
270
271



















272
273
274
275
276
277
278
...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
        if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0;
      }
    }
  }
  if( z[i-1]=='/' ) return 0;
  return 1;
}
















/*
** Simplify a filename by
**

**  * removing any trailing and duplicate /
**  * removing /./
**  * removing /A/../
**
** Changes are made in-place.  Return the new name length.
*/
int file_simplify_name(char *z, int n){
  int i, j;
  if( n<0 ) n = strlen(z);


#if defined(_WIN32)
  for(i=0; i<n; i++){
    if( z[i]=='\\' ) z[i] = '/';
  }
#endif


  while( n>1 && z[n-1]=='/' ){ n--; }


  for(i=j=0; i<n; i++){










    if( z[i]=='/' ){
      if( z[i+1]=='/' ) continue;

      if( z[i+1]=='.' && (i+2==n || z[i+2]=='/') ){
        i += 1;
        continue;
      }





      if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/') ){
        while( j>0 && z[j-1]!='/' ){ j--; }
        if( j>0 ){ j--; }


        i += 2;
        continue;
      }
    }
    z[j++] = z[i];

  }

  z[j] = 0;
  return j;
}




















/*
** Compute a canonical pathname for a file or directory.
** Make the name absolute if it is relative.
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
................................................................................
  int i;
  Blob x;
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    char zBuf[100];
    const char *zName = g.argv[i];
    file_canonical_name(zName, &x);
    printf("%s\n", blob_buffer(&x));
    blob_reset(&x);
    sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName));
    printf("  file_size   = %s\n", zBuf);
    sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName));
    printf("  file_mtime  = %s\n", zBuf);
    printf("  file_isfile = %d\n", file_isfile(zName));
    printf("  file_isexe  = %d\n", file_isexe(zName));







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>









>
>





>
>

>
>

>
>
>
>
>
>
>
>
>
>

<
>




>
>
>
>
>
|
<
<
>
>




|
>

>



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

287
288
289
290
291
292
293
294
295
296
297


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
        if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0;
      }
    }
  }
  if( z[i-1]=='/' ) return 0;
  return 1;
}

/*
** If the last component of the pathname in z[0]..z[j-1] is something
** other than ".." then back it out and return true.  If the last
** component is empty or if it is ".." then return false.
*/
static int backup_dir(const char *z, int *pJ){
  int j = *pJ;
  int i;
  if( j<=0 ) return 0;
  for(i=j-1; i>0 && z[i-1]!='/'; i--){}
  if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
  *pJ = i-1;
  return 1;
}

/*
** Simplify a filename by
**
**  * Convert all \ into / on windows
**  * removing any trailing and duplicate /
**  * removing /./
**  * removing /A/../
**
** Changes are made in-place.  Return the new name length.
*/
int file_simplify_name(char *z, int n){
  int i, j;
  if( n<0 ) n = strlen(z);

  /* On windows convert all \ characters to / */
#if defined(_WIN32)
  for(i=0; i<n; i++){
    if( z[i]=='\\' ) z[i] = '/';
  }
#endif

  /* Removing trailing "/" characters */
  while( n>1 && z[n-1]=='/' ){ n--; }

  /* Remove duplicate '/' characters */
  for(i=j=0; i<n; i++){
    z[j++] = z[i];
    while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
  }
  n = j;

  /* Skip over zero or more initial "./" sequences */
  for(i=0; i<n-1 && z[i]=='.' && z[i+1]=='/'; i+=2){}

  /* Begin copying from z[i] back to z[j]... */
  for(j=0; i<n; i++){
    if( z[i]=='/' ){

      /* Skip over internal "/." directory components */
      if( z[i+1]=='.' && (i+2==n || z[i+2]=='/') ){
        i += 1;
        continue;
      }

      /* If this is a "/.." directory component then back out the
      ** previous term of the directory if it is something other than ".."
      ** or "."
      */
      if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/')


       && backup_dir(z, &j)
      ){
        i += 2;
        continue;
      }
    }
    if( j>=0 ) z[j] = z[i];
    j++;
  }
  if( j==0 ) z[j++] = '.';
  z[j] = 0;
  return j;
}

/*
** COMMAND: test-simplify-name
**
** %fossil test-simplify-name FILENAME...
**
** Print the simplified versions of each FILENAME.
*/
void cmd_test_simplify_name(void){
  int i;
  char *z;
  for(i=2; i<g.argc; i++){
    z = mprintf("%s", g.argv[i]);
    printf("[%s] -> ", z);
    file_simplify_name(z, -1);
    printf("[%s]\n", z);
    fossil_free(z);
  }
}

/*
** Compute a canonical pathname for a file or directory.
** Make the name absolute if it is relative.
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
................................................................................
  int i;
  Blob x;
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    char zBuf[100];
    const char *zName = g.argv[i];
    file_canonical_name(zName, &x);
    printf("[%s] -> [%s]\n", zName, blob_buffer(&x));
    blob_reset(&x);
    sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName));
    printf("  file_size   = %s\n", zBuf);
    sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName));
    printf("  file_mtime  = %s\n", zBuf);
    printf("  file_isfile = %d\n", file_isfile(zName));
    printf("  file_isexe  = %d\n", file_isexe(zName));