| Summary: | 1Cv77: Не работает определение существования каталога | ||
|---|---|---|---|
| Product: | WINE@Etersoft | Reporter: | Vitaly Lipatov <lav> |
| Component: | Файловые операции | Assignee: | Константин Кондратюк <kondratyuk> |
| Status: | CLOSED FIXED | QA Contact: | Денис Баранов <baraka> |
| Severity: | normal | ||
| Priority: | P2 | CC: | baraka, ivan |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Заявки RT: | Связано с: | ||
| Дата напоминания: | |||
| Bug Depends on: | 59, 129, 901 | ||
| Bug Blocks: | 42, 584, 3589 | ||
| Attachments: | 1C обработка | ||
Тестирование показало разлисие в результатах функции ФС.СуществуетФайл: Строка Windows Wine C: Есть Нет C:\ Нет Нет С Нет Нет COM Нет Нет COM: Нет Нет COM1 Есть Нет NUL Есть Нет PRN Есть Нет AUX Есть Нет COM9 Есть Нет C:\Program files Есть Есть C:\Program files\ Есть Нет C:\windows\ Есть Нет C:\windows Есть Есть C:\windows\notepad.exe Есть Есть C:\windows\notepad.exe\ Есть Нет AUX\ Есть Нет LPT9\ Есть Нет тестирование функции FindFirstFileExW с параметром fSearchOp=FindSearchNameMatch
обнаружило только различия в:
Путь Windows Wine
С: есть (в cFileName нет
показывает
название текущего
каталога)
NUL есть нет
PRN есть нет
AUX есть нет
COM9 есть нет
+ остальные Дос-устройства
При тестированиии была допущена ошибка. Конфигурация Wine соответствовала Windows 98, а сравнение проводилось с Windows 2003. После нахождения этой ошибки выяснилось, что в Windows 95\98\Me пути со знаком '\' на конце не определялись. В последующих версиях Windows (NT4 SP5, 2000, XP, 2003) такие пути определяются и аналогичны пути без '\' на конце. Поскольку для нужд 1С в Wine используется режим Windows 98 -> выше указанная ситуация является корректной Принято решение изменить поведение WINE на соответствующее W2K. Отредактирован тестировщик для функции FindFirstFileExW.
Конечное тестирование показало несоответствие определения путей:
Путь В Win98 существует (1), не существует (0)
{"C:", 1},
{"NUL", 1},
{"AUX", 1},
{"PRN", 1},
{"NUL: ", 1},
{"NUL:.txt", 1},
{"NUL:357jhg", 1},
{"NUL:::", 1},
{"lpt1:", 1},
{"CoM4:", 1},
{"lpt9:", 1},
{"con:", 1},
{"\\LPT8", 1},
{"\\NUL", 1},
{"/NUL::::.. 11,,354--++", 1},
{"\\NUL::::.. 11,,354--++", 1},
{"e:NUl", 1},
{"e:nuL::::.. 11,,354--++", 1},
{"c:nuL::::.. 11,,354--++", 1},
{"C:///nuL::::.. 11,,354--++", 1},
{"c:///prograM fIleS\\LpT8::::.. 11,,354--++", 1},
{"c:NUL", 1},
{"c:\\nul::", 1},
{"c:prn:aaa", 1},
{"c:PRN:.txt", 1},
{"c:aux:.txt...", 1},
{"c:prn:.txt:", 1},
{"c:nul:aaa", 1},
{"c:com5:", 1},
{"c:nul. . . :", 1},
{"c:nul . . :", 1},
{"c:prn ", 1},
{"c:prn.......", 1},
{"c:prn... ...", 1},
{"c:NUL .... ", 1}
К сожалению не была проверена функция RtlIsDosDeviceName_U на распознавание Dos-
путей и все исправления вводились исходя из выше приведенного теста. Патч для
ntdll/path.c:
Index: path.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/path.c,v
retrieving revision 1.37
diff -u -u -r1.37 path.c
--- path.c 28 Nov 2005 20:10:41 -0000 1.37
+++ path.c 11 May 2006 08:37:39 -0000
@@ -339,27 +339,25 @@
}
end = dos_name + strlenW(dos_name) - 1;
- if (end >= dos_name && *end == ':') end--; /* remove trailing ':' */
/* find start of file name */
for (start = end; start >= dos_name; start--)
{
if (IS_SEPARATOR(start[0])) break;
/* check for ':' but ignore if before extension (for things like NUL:.
txt) */
- if (start[0] == ':' && start[1] != '.') break;
}
start++;
/* remove extension */
- if ((p = strchrW( start, '.' )))
+ if ((p = strchrW( start, ':' )))
{
end = p - 1;
- if (end >= dos_name && *end == ':') end--; /* remove trailing ':'
before extension */
+ while (end >= dos_name && ((*end == ' ') || (*end == '.') || (*end ==
':'))) end--; /* remove trailing ':', ' ', '.' before extension */
}
else
{
- /* no extension, remove trailing spaces */
- while (end >= dos_name && *end == ' ') end--;
+ /* no extension, remove trailing ' ', '.' */
+ while (end >= dos_name && ((*end == ' ') || (*end == '.'))) end--;
}
/* now we have a potential device name between start and end, check it */
ш патч для kernel/file.c:
Index: file.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/file.c,v
retrieving revision 1.51
diff -u -u -r1.51 file.c
--- file.c 3 Apr 2006 19:46:58 -0000 1.51
+++ file.c 11 May 2006 08:54:19 -0000
@@ -1546,12 +1546,14 @@
LPVOID data, FINDEX_SEARCH_OPS search_op,
LPVOID filter, DWORD flags)
{
- WCHAR *mask, *p;
+ WCHAR *mask, *p, *tmp;
FIND_FIRST_INFO *info = NULL;
UNICODE_STRING nt_name;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
NTSTATUS status;
+ ULONG dos_device;
+ DWORD sz;
TRACE("%s %d %p %d %p %lx\n", debugstr_w(filename), level, data, search_op,
filter, flags);
@@ -1573,38 +1575,136 @@
return INVALID_HANDLE_VALUE;
}
- if (!mask || !*mask)
+ if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
{
- SetLastError( ERROR_FILE_NOT_FOUND );
- goto error;
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ RtlFreeUnicodeString( &nt_name );
+ return INVALID_HANDLE_VALUE;
}
- if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
+ if(RtlDetermineDosPathNameType_U( filename ) == RELATIVE_DRIVE_PATH )
{
- SetLastError( ERROR_NOT_ENOUGH_MEMORY );
- goto error;
+ if (!(tmp = RtlAllocateHeap(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR
))))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ if(!(sz = GetCurrentDirectoryW(MAX_PATH, tmp)))
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, tmp );
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ /* for current DRIVE or NOT */
+ if( nt_name.Buffer[4] == tmp[0])
+ {
+ tmp[sz] = '\\';
+ sz++;
+ memcpy((void *)(tmp + sz), (void *)(filename + 2),
(strlenW(filename)-1)*sizeof(WCHAR) );
+ }
+ else
+ {
+ memcpy((void *)tmp, (void *)filename, 2*sizeof(WCHAR) );
+ tmp[2] = '\\';
+ memcpy((void *)(tmp + 3), (void *)(filename + 2),
(strlenW(filename)-1)*sizeof(WCHAR) );
+ }
+ dos_device = RtlIsDosDeviceName_U( tmp );
+ }
+ else
+ {
+ if (!(tmp = RtlAllocateHeap(GetProcessHeap(), 0, (strlenW(filename) +
1)*sizeof(WCHAR))))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ memcpy(tmp, filename, (strlenW(filename) + 1)*sizeof(WCHAR) );
}
- if (!RtlCreateUnicodeString( &info->mask, mask ))
+
+ if ((!mask && !dos_device) || (mask && !*mask))
{
- SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ SetLastError( ERROR_FILE_NOT_FOUND );
goto error;
}
- /* truncate dir name before mask */
- *mask = 0;
- nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
-
- /* check if path is the root of the drive */
- info->is_root = FALSE;
- p = nt_name.Buffer + 4; /* skip \ш\ prefix */
- if (p[0] && p[1] == ':')
- {
- p += 2;
- while (*p == '\\') p++;
- info->is_root = (*p == 0);
+ /*If there is a DOS device*/
+ if(!mask && dos_device)
+ {
+ WIN32_FIND_DATAW *d = data;
+
+ /*LOWORD(dos_device) - quantity of symbols in the DOS device name (NUL,
LPT1,...)
+ filename + HIWORD(dos_device) - points to the Dos device name's
beginning */
+ /*Initialize info.mask with NULL*/
+ if (!( RtlInitUnicodeStringEx( &info->mask, NULL ) == STATUS_SUCCESS) )
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ /* Free old nt_name */
+ RtlFreeUnicodeString( &nt_name );
+
+ info->is_root = FALSE;
+ /*Initialize nt_name*/
+ if(HIWORD(dos_device))
+ {
+ nt_name.Length = 4*sizeof(WCHAR) + HIWORD(dos_device);
+ nt_name.MaximumLength = nt_name.Length + sizeof(WCHAR);
+ }
+ /* for "PRN", "NUL" & etc. */
+ else
+ {
+ nt_name.Length = 5*sizeof(WCHAR);
+ nt_name.MaximumLength = nt_name.Length + sizeof(WCHAR);
+ }
+
+ if (!(nt_name.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, nt_name.
MaximumLength)))
+ {
+ RtlFreeUnicodeString( &info->mask );
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ HeapFree( GetProcessHeap(), 0, info );
+ return INVALID_HANDLE_VALUE;
+ }
+ /*convert to NT' style path*/
+ nt_name.Buffer[0] = '\\';
+ nt_name.Buffer[1] = nt_name.Buffer[2] = '?';
+ nt_name.Buffer[3] = '\\';
+ memcpy( (void *)(nt_name.Buffer + 4), tmp, HIWORD(dos_device));
+ nt_name.Buffer[nt_name.Length/sizeof(WCHAR)] = 0;
+ /* for "\NUL" & for "PRN", "NUL" & etc. */
+ if(!HIWORD(dos_device) || nt_name.Buffer[4] == '\\')
+ {
+ nt_name.Buffer[4] = '/';
+ };
+
+ memset(d, 0, sizeof(*d));
+ d->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
+ memcpy( d->cFileName, tmp + HIWORD(dos_device)/sizeof(WCHAR),
LOWORD(dos_device));
+
+ RtlFreeHeap( GetProcessHeap(), 0, tmp );
}
+ else
+ {
+ if (!RtlCreateUnicodeString( &info->mask, mask ))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ /* truncate dir name before mask */
+ *mask = 0;
+ nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
+
+ /* check if path is the root of the drive */
+ info->is_root = FALSE;
+ p = nt_name.Buffer + 4; /* skip \ш\ prefix */
+ if (p[0] && p[1] == ':')
+ {
+ p += 2;
+ while (*p == '\\') p++;
+ info->is_root = (*p == 0);
+ }
+ }
+ /*Initialize attr*/
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE;
@@ -1612,6 +1712,7 @@
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
+ /* check if nt_name is existing directory */
status = NtOpenFile( &info->handle, GENERIC_READ, &attr, &io,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
@@ -1630,12 +1731,12 @@
info->data_len = 0;
info->search_op = search_op;
- if (!FindNextFileW( (HANDLE)info, data ))
+ if (!dos_device && !FindNextFileW( (HANDLE)info, data ))
{
TRACE( "%s not found\n", debugstr_w(filename) );
FindClose( (HANDLE)info );
SetLastError( ERROR_FILE_NOT_FOUND );
- return INVALID_HANDLE_VALUE;
+ goto error;
}
return (HANDLE)info;
Но поскольку не была оттестирована функция RtlIsDosDeviceName_U, принимать эти
исправления в счет нельзя.
1. Так и нет и намёка на исправление проблемы с C:\WINDOWS\ 2. Тест не приложен к баге (через Создать приложение - не надо вписывать патчи в комментарии) Проблема в том, что 1С на NT системе убирает слэш в конце строки, если он есть, а в Win9X - не убирает. Вывод - указание \ в конце пути неверно и не должно использоваться. Выставить версию WINE в Win2000 не представляется возможным из-за баги #129. К сборке добавлен патч, убирающий последний '\' при вызове FindFirstFileExA(). Пока что убирает для всех версий windows, и это неправильно, потому что в NT-системах файл с именем "c:\windows\" не будет найден. Добавил проверку версии Windows. Теперь при вызове в режиме WinXP функциональность идентична windows. Осталось проверить для win98. Тест запущенный на windows 98 показал Target file is c:\windows. The first file found is windows Target file is c:\windows\. Invalid File Handle Тест показывает, что и в Windows 98 "c:\windows\" не понимается. Если нужно, можно оставить хак, добавляющий эту "лишнюю" функциональность. Только нужно ли? Created attachment 176 [details]
1C обработка
Эта обработка просто проверяет существует или нет указанный каталог. Проверяемый каталог возможно указать при работе с обработкой.
Бага в непонятном состоянии.
Добавление / приводит к зависанию установщика конфигурации 1С 8.1
на FindFirstFile("C:\WINDOWS\TEMP") - оно бесконечно вызывается, с FindNextFile...
Решено проверкой на etersoft_1version() Теперь преобразование только для 1С 7.7 К 1.0.6-eter11 патч восстановлен: Created commit 15d89e9: remove last slash from the path (fix eterbug#106) Начиная с 1.0.11 включили режим Windows XP для 1С 7.7 по умолчанию. |
Нужно проверить функционирование следующего кода: Если ФС.СуществуетФайл("C:\WINDOWS\")=0 тогда Сообщить("Нет каталога"); шначе Сообщить("Есть каталог"); КонецЕсли;