Check-in [fe6ef89f5f]
Not logged in

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

Overview
Comment:Another update for[9919dfbbaa]: Make sure reallocated buffers always grow, guard all buffer writes by overflow checks (next time use blobs), make sure the `case-sensitive' setting and command-line option are followed, and use brute force to achieve binary (vs.linguistic) file name comparison (only on older versions of Windows).
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: fe6ef89f5f9d23e09c899e854d6dc796ababc59fdf14068477e1bee0bd4bd821
User & Date: florian 2024-10-19 14:03:00.000
References
2024-10-20
04:24
Fix an oversight in [fe6ef89f5f]. check-in: 95c1490cd6 user: florian tags: trunk
Context
2024-10-19
14:10
Resolve accidental fork. check-in: 6041e258ba user: florian tags: trunk
14:03
Another update for[9919dfbbaa]: Make sure reallocated buffers always grow, guard all buffer writes by overflow checks (next time use blobs), make sure the `case-sensitive' setting and command-line option are followed, and use brute force to achieve binary (vs.linguistic) file name comparison (only on older versions of Windows). check-in: fe6ef89f5f user: florian tags: trunk
2024-10-17
16:54
Merge brickviking's documentation typo fixes to trunk. check-in: efd79f87f5 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/file.c.
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
      fossil_path_free(zUtf8);
    }
    closedir(d);
  }
  fossil_path_free(zNative);
  if( zResult==0 ) zResult = fossil_strdup(zPath);
  return zResult;
#else /* _WIN32 */
  return win32_file_case_preferred_name(zDir,zPath);
#endif /* _WIN32 */
}

/*
** COMMAND: test-case-filename
**
** Usage: fossil test-case-filename DIRECTORY PATH PATH PATH ....
**







|

|







1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
      fossil_path_free(zUtf8);
    }
    closedir(d);
  }
  fossil_path_free(zNative);
  if( zResult==0 ) zResult = fossil_strdup(zPath);
  return zResult;
#else /* !_WIN32 */
  return win32_file_case_preferred_name(zDir,zPath);
#endif /* !_WIN32 */
}

/*
** COMMAND: test-case-filename
**
** Usage: fossil test-case-filename DIRECTORY PATH PATH PATH ....
**
Changes to src/winfile.c.
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
  for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
  strncpy(zBuf, zUtf8, nBuf);
  fossil_path_free(zUtf8);
}

/* Perform case-insensitive comparison of two UTF-16 file names. Try to load the
** CompareStringOrdinal() function on Windows Vista and newer, and resort to the
** lstrcmpiW() function on Windows XP.





*/
int win32_compare_filenames_nocase(
  const wchar_t *fn1,
  const wchar_t *fn2
){
  static FARPROC fnCompareStringOrdinal;


  static int tried_CompareStringOrdinal;

  if( !tried_CompareStringOrdinal ){
    fnCompareStringOrdinal =
      GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal");
    tried_CompareStringOrdinal = 1;
  }
  if( fnCompareStringOrdinal ){
    return -2 + fnCompareStringOrdinal(fn1,-1,fn2,-1,1);













  }else{

    return lstrcmpiW(fn1,fn2);

  }


}

/* Helper macros to deal with directory separators. */
#define IS_DIRSEP(s,i) ( s[i]=='/' || s[i]=='\\' )
#define NEXT_DIRSEP(s,i) while( s[i] && s[i]!='/' && s[i]!='\\' ){i++;}

/* The Win32 version of file_case_preferred_name() from file.c, which is able to







|
>
>
>
>
>

|




>
>
|
>
|


|


|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>

>
>







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
337
338
339
340
341
342
343
344
345
346
347
  for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
  strncpy(zBuf, zUtf8, nBuf);
  fossil_path_free(zUtf8);
}

/* Perform case-insensitive comparison of two UTF-16 file names. Try to load the
** CompareStringOrdinal() function on Windows Vista and newer, and resort to the
** RtlEqualUnicodeString() function on Windows XP.
** The dance to invoke RtlEqualUnicodeString() is necessary because lstrcmpiW()
** performs linguistic comparison, while the former performs binary comparison.
** As an example, matching "ß" (U+00DF Latin Small Letter Sharp S) with "ss" is
** undesirable in file name comparison, so lstrcmpiW() is only invoked in cases
** that are technically impossible and contradicting all known laws of physics.
*/
int win32_filenames_equal_nocase(
  const wchar_t *fn1,
  const wchar_t *fn2
){
  static FARPROC fnCompareStringOrdinal;
  static FARPROC fnRtlInitUnicodeString;
  static FARPROC fnRtlEqualUnicodeString;
  static int loaded_CompareStringOrdinal;
  static int loaded_RtlUnicodeStringAPIs;
  if( !loaded_CompareStringOrdinal ){
    fnCompareStringOrdinal =
      GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal");
    loaded_CompareStringOrdinal = 1;
  }
  if( fnCompareStringOrdinal ){
    return fnCompareStringOrdinal(fn1,-1,fn2,-1,1)-2==0;
  }
  if( !loaded_RtlUnicodeStringAPIs ){
    fnRtlInitUnicodeString =
      GetProcAddress(GetModuleHandleA("ntdll"),"RtlInitUnicodeString");
    fnRtlEqualUnicodeString =
      GetProcAddress(GetModuleHandleA("ntdll"),"RtlEqualUnicodeString");
    loaded_RtlUnicodeStringAPIs = 1;
  }
  if( fnRtlInitUnicodeString && fnRtlEqualUnicodeString ){
    struct { /* UNICODE_STRING from <ntdef.h> */
      unsigned short Length;
      unsigned short MaximumLength;
      wchar_t *Buffer;
    } u1, u2;
    fnRtlInitUnicodeString(&u1,fn1);
    fnRtlInitUnicodeString(&u2,fn2);
    return (unsigned char)fnRtlEqualUnicodeString(&u1,&u2,1);
  }
  /* In what kind of strange parallel universe are we? */
  return lstrcmpiW(fn1,fn2)==0;
}

/* Helper macros to deal with directory separators. */
#define IS_DIRSEP(s,i) ( s[i]=='/' || s[i]=='\\' )
#define NEXT_DIRSEP(s,i) while( s[i] && s[i]!='/' && s[i]!='\\' ){i++;}

/* The Win32 version of file_case_preferred_name() from file.c, which is able to
345
346
347
348
349
350
351











352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376




377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
** information class FILE_CASE_SENSITIVE_INFORMATION. So this function may be
** changed to act like fossil_strdup() for files located in such directories.
*/
char *win32_file_case_preferred_name(
  const char *zBase,
  const char *zPath
){











  int cchBase = strlen(zBase);
  int cchPath = strlen(zPath);
  int cchBuf = cchBase + cchPath + 2; /* + NULL + optional directory slash */
  int cchRes = cchPath + 1;           /* + NULL */
  char *zBuf = fossil_malloc(cchBuf);
  char *zRes = fossil_malloc(cchRes);
  int ncUsed = 0;
  int i, j;
  memcpy(zBuf,zBase,cchBase);
  if( !IS_DIRSEP(zBuf,cchBase-1) ){
    zBuf[cchBase++]=L'/';
  }
  memcpy(zBuf+cchBase,zPath,cchPath+1);
  i = j = cchBase;
  while( 1 ){
    WIN32_FIND_DATAW fd;
    HANDLE hFind;
    wchar_t *wzBuf;
    char *zCompBuf = 0;
    char *zComp = &zBuf[i];
    int cchComp;
    char chSep;
    int fDone;
    if( IS_DIRSEP(zBuf,i) ){
      zRes[ncUsed++] = zBuf[i];




      i = j = i+1;
      continue;
    }
    NEXT_DIRSEP(zBuf,j);
    fDone = zBuf[j]==0;
    chSep = zBuf[j];
    zBuf[j] = 0;                /* Truncate working buffer. */
    wzBuf = fossil_utf8_to_path(zBuf,0);
    hFind = FindFirstFileW(wzBuf,&fd);
    if( hFind!=INVALID_HANDLE_VALUE ){
      wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
      FindClose(hFind);
      /* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
      if( win32_compare_filenames_nocase(wzComp,fd.cFileName)==0 ){
        zCompBuf = fossil_path_to_utf8(fd.cFileName);
        zComp = zCompBuf;
      }
      fossil_path_free(wzComp);
    }
    fossil_path_free(wzBuf);
    cchComp = strlen(zComp);
    if( ncUsed+cchComp+1>cchRes ){
      cchRes = ncUsed + cchComp + 32; /* While at it, add some extra space. */
      zRes = fossil_realloc(zRes,cchRes);
    }
    memcpy(zRes+ncUsed,zComp,cchComp);
    ncUsed += cchComp;
    if( zCompBuf ){
      fossil_path_free(zCompBuf);
    }







>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
<

















>
>
>
>













|







|
|







370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
** information class FILE_CASE_SENSITIVE_INFORMATION. So this function may be
** changed to act like fossil_strdup() for files located in such directories.
*/
char *win32_file_case_preferred_name(
  const char *zBase,
  const char *zPath
){
  int cchBase;
  int cchPath;
  int cchBuf;
  int cchRes;
  char *zBuf;
  char *zRes;
  int ncUsed;
  int i, j;
  if( filenames_are_case_sensitive() ){
    return fossil_strdup(zPath);
  }
  cchBase = strlen(zBase);
  cchPath = strlen(zPath);
  cchBuf = cchBase + cchPath + 2; /* + NULL + optional directory slash */
  cchRes = cchPath + 1;           /* + NULL */
  zBuf = fossil_malloc(cchBuf);
  zRes = fossil_malloc(cchRes);
  ncUsed = 0;

  memcpy(zBuf,zBase,cchBase);
  if( !IS_DIRSEP(zBuf,cchBase-1) ){
    zBuf[cchBase++]=L'/';
  }
  memcpy(zBuf+cchBase,zPath,cchPath+1);
  i = j = cchBase;
  while( 1 ){
    WIN32_FIND_DATAW fd;
    HANDLE hFind;
    wchar_t *wzBuf;
    char *zCompBuf = 0;
    char *zComp = &zBuf[i];
    int cchComp;
    char chSep;
    int fDone;
    if( IS_DIRSEP(zBuf,i) ){
      zRes[ncUsed++] = zBuf[i];
      if( ncUsed+2>cchRes ){  /* Directory slash + NULL*/
        cchRes += 32;         /* Overprovisioning. */
        zRes = fossil_realloc(zRes,cchRes);
      }
      i = j = i+1;
      continue;
    }
    NEXT_DIRSEP(zBuf,j);
    fDone = zBuf[j]==0;
    chSep = zBuf[j];
    zBuf[j] = 0;                /* Truncate working buffer. */
    wzBuf = fossil_utf8_to_path(zBuf,0);
    hFind = FindFirstFileW(wzBuf,&fd);
    if( hFind!=INVALID_HANDLE_VALUE ){
      wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
      FindClose(hFind);
      /* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
      if( win32_filenames_equal_nocase(wzComp,fd.cFileName) ){
        zCompBuf = fossil_path_to_utf8(fd.cFileName);
        zComp = zCompBuf;
      }
      fossil_path_free(wzComp);
    }
    fossil_path_free(wzBuf);
    cchComp = strlen(zComp);
    if( ncUsed+cchComp+1>cchRes ){  /* Current component + NULL */
      cchRes += cchComp + 32;       /* Overprovisioning. */
      zRes = fossil_realloc(zRes,cchRes);
    }
    memcpy(zRes+ncUsed,zComp,cchComp);
    ncUsed += cchComp;
    if( zCompBuf ){
      fossil_path_free(zCompBuf);
    }