Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

PathTooLongException czyli MAX_PATH i ::$DATA a .NET oraz problemy z LoadLibrary

Dziś kilka słów o tym, czego możemy spodziewać się po .NET jeśli idzie o niektóre możliwości systemu plików.

- Panie Michale, to JEDNYM słowem, jak to jest z tym wsparciem dla niektórych rzadziej używanych funkcji systemu plików w .NET?
- Dobrze.
- A dwoma słowami?
- Nie dobrze.

Nudne wprowadzenie

Wszystkie programy .NET są jednocześnie aplikacjami Win32, co oznacza, że pracują w ramach podsystemu Windows, który realizowany jest przez proces csrss.exe. Jego nazwa rozwija się do Client/Server Run-Time Subsystem i pozostała niezmieniona  od czasów prehistorycznych, kiedy to wszystkie 3 podsystemy (Windows, POSIX oraz OS/2) miały być implementowane jako wątki w ramach jednego wspólnego procesu, jednak w późniejszych wersjach Windows NT każdy z podsystemów otrzymał swój własny proces i obecnie wszystkie są uruchamiane przez Session Managera (smss.exe). Wszystkie, czyli od Windows XP podsystem Windows z jego csrss.exe oraz POSIX z psxss.exe, przy czym tylko ten pierwszy jest domyślnie zainstalowany i ładowany przy starcie.
Dalej, smss.exe jest aplikacją natywną, co oznacza, iż korzysta wyłącznie z usług natywnych, dostarczanych m.in. przez bibliotekę ntdll.dll i nie jest zależny w jakikolwiek sposób od API podsystemu Win32.
Csrss dostarcza swoje usługi w ramach zestawu bibliotek Win32, a zatem kernel32.dll, advapi32.dll, user32.dll oraz gdi32.dll (podstawa Win32 API), a sam realizuje obsługę okien (i nie tylko to) w ramach sterownika trybu jądra win32k.sys (ciekawe skąd taka nazwa? ;)).
Z pomocą wspomnianych wyżej bibliotek podsystem Win32 opakowuje podstawowe usługi systemowe, przy okazji nierzadko okrajając pewną ich funkcjonalność do własnych potrzeb, którymi muszą się zadowolić aplikacje Win32.
Na potrzeby przetargów rządowych w Stanach, Microsoft utrzymuje zgodność Windowsów z kolejnymi wersjami POSIXa, co wiąże się z koniecznością implementowania pewnych funkcjonalności w różnych miejscach systemu, w tym m.in. w systemie plików NTFS. I o ile można z tych funkcjonalności korzystać garściami w ramach podsystemu POSIX, to już w ramach Win32 tak różowo nie jest. Nie jest tak, ponieważ podsystem Win32 nie udostępnia wszystkiego, a tylko część, a to, czego nie daje, skrzętnie maskuje przed swoimi procesami.
Po tym nieco przydługim wstępie kilka praktycznych przykładów.

Przykłady

  1. Dłuuugie ścieżki ( > MAX_PATH).
    Jedną z takich funkcjonalności jest obsługa długich ścieżek. W ramach NTFS ścieżka może mieć długość 32767 znaków (w przybliżeniu, bo wlicza się w to jeszcze \device\HarddiskVolumeN, nie wspominając o \GLOBAL??\), a pojedynczy element, czyli nazwa katalogu, tudzież pliku nie może być dłuższa niż 255 znaków. Win32 definiuje jednak stałą MAX_PATH = 260, która określa maksymalną długość ścieżki (= 256 znaków na katalogi + nazwę pliku z rozszerzeniem + 3 znaki ([LITERKA DYSKU, np. c]:\) + 1 znak na kończący ścieżkę null). Czy to dużo? Chyba jednak nie, skoro od Visty ścieżki typu C:\Documents and Settings\[user]\Moje Dokumenty\... zostały wreszcie skrócone do c:\Users\[user]\Documents\... (wystarczy sobie przypomnieć ścieżki niektórych aplikacji z Application Data, dla których pozostawało nierzadko ledwie kilkadziesiąt znaków dla użytkownika).
  2. Alternatywne strumienie plików (ADS).
    Kolejną, rzadko znaną i używaną funkcjonalnością są alternatywne strumienie plików. Ostatnio Paweł Łukasik pisał i mówił o nich, więc mi pozostaje tylko podać link do Jego wpisu :).
    Oryginalnie zaimplementowane na potrzeby współpracy z Macintoshami, używane są przez różne elementu systemu (ikonka ulubionych, podsumowanie plików, etc.), o czym nie zawsze wiemy. A nie wiemy dlatego, ponieważ nie ma żadnego narzędzia w shellu (Eksplorator Windows, cmd), który poinformowałby nas o tym, jakie dany plik ma strumienie. Eksplorator potrafi interpretować niektóre strumienie i pokazuje nam to w dodatkowych zakładkach, ale to są działania 'od przypadku do przypadku'. Oczywiście pozostaje nam posiłkowanie się programami typu streams z pakietu Sysinternals Suite, ale do wygody im daleko.
  3. Nietypowe nazwy plików.
    Trochę tego jest. Ja skupię się w moich dalszych zabawach na plikach, których nazwa kończy się spacjami. Czyli np. "test.txt " (1 spacja), "test.txt  " (2 spacje)
  4. Zastrzeżone nazwy.
    CON, COM1, PRN, etc.. Całe stado nazw, których używanie oznacza proszenie się o kłopoty. Eksplorator kompletnie sobie z nimi nie radzi, podobnie cała rzesza narzędzi konsolowych.

Pełen opis konwencji nazewniczych plików znajduje się na stronach MSDN i gorąco zachęcam do zajrzenia na tę właśnie stronę.

"For file I/O, the "\\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system."

Uwagę szczególnie zwraca ciąg "\\?\" i informacja, iż użycie go na początku nazwy stanowi sygnał dla funkcji podsystemu Win32, aby przepuścić cały ciąg bez parsowania.

Testy

W swoich zabawach skupiłem się na 4 powyższych przypadkach i postanowiłem sprawdzić jak to jest z .NETem. Użyłem prostych metod zapisujących przykładowe dane do pliku i obserwowałem co gdzie działa, a co nie.

public static void CreateFileWithDataNET(string fileName, string data)
{
 using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
 {
    using (TextWriter writer = new StreamWriter(stream, Encoding.Unicode))
    {
     writer.Write(data);
    }
 }
}
public static void CreateFileWithData(string fileName, string data)
{
 using (SafeFileHandle fileHandle = Win32.CreateFile(fileName, FileAccess.ReadWrite, FileShare.None, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero))
 {
    using (FileStream stream = new FileStream(fileHandle, FileAccess.ReadWrite))
    {
     using (TextWriter writer = new StreamWriter(stream, System.Text.Encoding.Unicode))
     {
       writer.WriteLine(data);
     }
    }
 }
}

przy czym CreateFile zaimportowałem następująco (za pinvoke.net):

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern SafeFileHandle CreateFile(
    string fileName,
    [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
    [MarshalAs(UnmanagedType.U4)] FileShare fileShare,
    IntPtr securityAttributes,
    [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
    int flags,
    IntPtr template);

Następnie przeprowadziłem po 4 testy dla każdego z podanych wyżej 4 przypadków:

  1. CreateFileWithDataNET(sciezka)
  2. CreateFileWithDataNET(\\?\sciezka)
  3. CreateFileWithData(sciezka)
  4. CreateFileWithData(\\?\sciezka)

Wyniki powyższych testów, wraz ze zwracanymi wyjątkami zestawiam poniżej. Na końcu podana jest lista plików, które zostały utworzone.

>NTFSAndNET

------ LONG PATH TEST #1 - .NET only - no prefix ------
File name:
C:\Temp\Tests\Test_1_Long_012345678901234567890123456789012345678901234567890123
45678901234567890123456789012345678901234567890123456789012345678901234567890123
45678901234567890123456789012345678901234567890123456789012345678901234567890123
45678901234567890.txt
Exception [System.IO.PathTooLongException]: The specified path, file name, or bo
th are too long. The fully qualified file name must be less than 260 characters,
and the directory name must be less than 248 characters.
------ LONG PATH TEST #2 - .NET only - with prefix ------
File name:
\\?\C:\Temp\Tests\Test_2_Long_01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456.txt
Exception [System.IO.PathTooLongException]: The specified path, file name, or bo
th are too long. The fully qualified file name must be less than 260 characters,
and the directory name must be less than 248 characters.
------ LONG PATH TEST #3 - PInvoke - no prefix ------
File name:
C:\Temp\Tests\Test_3_Long_012345678901234567890123456789012345678901234567890123
45678901234567890123456789012345678901234567890123456789012345678901234567890123
45678901234567890123456789012345678901234567890123456789012345678901234567890123
45678901234567890.txt
Exception [System.ArgumentException]: Invalid handle.
Parameter name: handle
------ LONG PATH TEST #4 - PInvoke - with prefix ------
File name:
\\?\C:\Temp\Tests\Test_4_Long_01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456.txt
------ FILE NAME WITH SPACES TEST #5 - .NET only - no prefix ------
File name:
-|C:\Temp\Tests\Test_5_Spaces.txt |-
File name:
-|C:\Temp\Tests\Test_5_Spaces.txt  |-
------ FILE NAME WITH SPACES TEST #6 - .NET only - with prefix ------
File name:
-|\\?\C:\Temp\Tests\Test_6_Spaces.txt |-
Exception [System.ArgumentException]: Illegal characters in path.
File name:
-|\\?\C:\Temp\Tests\Test_6_Spaces.txt  |-
Exception [System.ArgumentException]: Illegal characters in path.
------ FILE NAME WITH SPACES TEST #7 - PInvoke - no prefix ------
File name:
-|C:\Temp\Tests\Test_7_Spaces.txt |-
File name:
-|C:\Temp\Tests\Test_7_Spaces.txt  |-
------ FILE NAME WITH SPACES TEST #8 - PInvoke - with prefix ------
File name:
-|\\?\C:\Temp\Tests\Test_8_Spaces.txt |-
File name:
-|\\?\C:\Temp\Tests\Test_8_Spaces.txt  |-
------ ALTERNATE DATA STREAM #9 - .NET only - no prefix ------
File name:
-|C:\Temp\Tests\Test_9_Stream_DATA.txt::$DATA|-
Exception [System.NotSupportedException]: The given path's format is not
supported.
File name:
-|C:\Temp\Tests\Test_9_Stream_test.txt:test|-
Exception [System.NotSupportedException]: The given path's format is not
supported.
------ ALTERNATE DATA STREAM #10 - .NET only - with prefix ------
File name:
-|\\?\C:\Temp\Tests\Test_10_Stream_DATA.txt::$DATA|-
Exception [System.ArgumentException]: Illegal characters in path.
File name:
-|\\?\C:\Temp\Tests\Test_10_Stream_test.txt:test|-
Exception [System.ArgumentException]: Illegal characters in path.
------ ALTERNATE DATA STREAM #11 - PInvoke - no prefix ------
File name:
-|C:\Temp\Tests\Test_11_Stream_DATA.txt::$DATA|-
File name:
-|C:\Temp\Tests\Test_11_Stream_test.txt:test|-
------ ALTERNATE DATA STREAM #12 - PInvoke - with prefix ------
File name:
-|\\?\C:\Temp\Tests\Test_12_Stream_DATA.txt::$DATA|-
File name:
-|\\?\C:\Temp\Tests\Test_12_Stream_test.txt:test|-
------ RESERVED NAMES #13 - .NET only - no prefix ------
File name:
-|C:\Temp\Tests\COM3|-
Exception [System.ArgumentException]: FileStream will not open Win32 devices
such as disk partitions and tape drives. Avoid use of "\\.\" in the path.
------ RESERVED NAMES #14 - .NET only - with prefix ------
File name:
-|\\?\C:\Temp\Tests\COM4|-
Exception [System.ArgumentException]: Illegal characters in path.
------ RESERVED NAMES #15 - PInvoke - no prefix ------
File name:
-|C:\Temp\Tests\COM5|-
Exception [System.ArgumentException]: Invalid handle.
Parameter name: handle
------ RESERVED NAMES #16 - PInvoke - with prefix ------
File name:
-|\\?\C:\Temp\Tests\COM6|-
------ File list -----
|FILE_NAME| SIZE
|C:\Temp\Tests\COM6| 78
|C:\Temp\Tests\Test_11_Stream_DATA.txt| 74
|C:\Temp\Tests\Test_11_Stream_test.txt| 0
|C:\Temp\Tests\Test_12_Stream_DATA.txt| 78
|C:\Temp\Tests\Test_12_Stream_test.txt| 0
|C:\Temp\Tests\Test_4_Long_01234567890123456789012345678901234567890123456789012
34567890123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456.txt| 78
|C:\Temp\Tests\Test_5_Spaces.txt| 74
|C:\Temp\Tests\Test_7_Spaces.txt| 74
|C:\Temp\Tests\Test_8_Spaces.txt | 78
|C:\Temp\Tests\Test_8_Spaces.txt  | 78

Do powyższego zestawienia jeszcze wynik działania programu streams (tu uwaga - bez podania prefiksu w wywołaniu streams działa niepoprawnie)

>streams \\?\c:\temp\tests\*

Streams v1.56 - Enumerate alternate NTFS data streams
Copyright (C) 1999-2007 Mark Russinovich
Sysinternals - www.sysinternals.com

\\?\c:\temp\tests\Test_11_Stream_test.txt:
           :test:$DATA 74
\\?\c:\temp\tests\Test_12_Stream_test.txt:
           :test:$DATA 78

Streszczenie, proszę!

Gołym okiem widać, że bez posiłkowania się mechanizmami Platform Invocation nie jesteśmy w stanie skorzystać z żadnej z badanych funkcjonalności. I tak:
1. Do utworzenia pliku o długiej ścieżce musimy sięgnąć do pinvoke, a na początku dać prefiks \\?\. Bez tego dostaniemy tytułowy PathTooLongException, a w wersji natywnej bez prefiksu - ArgumentException.
2. Gdy próbujemy utworzyć plik ze spacją na końcu, a później drugi z dwiema spacjami, to .NET zrobi to, co robi podsystem Win32 - utnie z nazwy końcowe spacje i oba wywołania zapiszą dane w tym samym pliku. Ciekawe, że wersja .NETowa z prefiksem zwraca nam tym razem błąd ArgumentException i coś o 'Illegal characters', chociaż bez prefiksu po prostu zeżarła co trzeba. Tylko wersja natywna z prefiksem pozwoliła utworzyć dwa pliki ze spacjami na końcu, bez prefiksu pochłania końcowe spacje.
3. Utworzenie strumienia (nawet :$DATA, czyli podstawowego strumienia danych) bezpośrednio w .NET kończy się NotSupportedException, a w wersji z prefiksem - ArgumentException i znowu śpiewka o illegal characters. Wersja natywna w obu przypadkach (z- i bez- prefiksu) kończy się sukcesem i tworzone są odpowiednie pliki ze strumieniami.
4. Próba użycia nazwy zarezerwowanej prowadzi wprost do ArgumentException, poza wersją natywną z prefiksem, która po prostu tworzy odpowiedni plik.

Pogrzebmy trochę głębiej

Pojawia się zasadnicze pytanie: dlaczego, u licha, w .NET Framework, który powstał na długo po tym, jak w systemie plików Windows była gotowa obsługa długich ścieżek i plejady innych rzeczy, nie ma tychże funkcjonalności i borykamy się z przesławnym MAX_PATH? W samym rotorze udało mi się znaleźć 730 wystąpień MAX_PATH, a przecież to tylko fragment całego kodu (który i tak nie musi pokrywać się z kodem .NET).
Na blogu zespołu odpowiedzialnego za BCL pojawiła się jakiś czas temu krótka seria poświęcona problemowi MAX_PATH w .NET Framework. Ba, na codeplex udostępnionona nawet została biblioteka pozwalająca cieszyć się w pełni długimi ścieżkami.
Podstawowe przedstawiane tam argumenty dotyczą kodu 'third party', braku spójności w Win32 odnośnie obsługi prefiksu \\?\, a jako czołowy przykład podawana jest funkcja LoadLibrary z kernel32.dll. Za chwilę do niej wrócimy, jednak teraz skupmy się na braku konsystencji w shellu oraz API Win32.
Problem braku spójności jest przeogromny. Mając przed sobą Windows 7 Ultimate i sprawdzając zachowanie eksploratora, notatnika oraz kilku poleceń konsoli (w tym type, more, dir) oraz programów typu copy, xcopy, robocopy, widzę, że co narzędzie to inny zestaw problemów. Notatnik potrafi bez problemu otwierać pliki o długich ścieżkach, ale ze spacją na końcu to już nie tak bardzo, podobnie zresztą sprawa ma się w przypadku alternatywnych strumieni. Składni z prefiksem \\? 'nie rozumi', a narzędzia konsolowe są w tym przypadku dosyć tolerancyjne, choć niczego to nie rozwiązuje, ponieważ dalej nie potrafią np. skopiować do pliku o długiej nazwie.
Moglibyśmy się tak pastwić jeszcze długo, ale oszczędźmy sobie i Microsoftowi tego i wróćmy do tak często powtarzanego we wspomnianym wpisie przykładu funkcji LoadLibrary.

LoadLibrary

Jedna z podstawowych funkcji eksportowanych przez kernel32.dll, pozwala na dynamiczne ładowanie modułu do przestrzeni adresowej procesu. Na pewno jeszcze wrócę do tej funkcji w przyszłych wpisach, teraz jednak skupimy się na jednej, bardzo bolesnej przypadłości: nie obsługuje prefiksu \\? w przypadku nazw plików. Co to dla nas oznacza?
Po pierwsze, w przypadku statycznie zlinkowanych bibliotek (dodanych jako referencje podczas kompilacji), CLR używa LoadLibrary i oczywiście nie ma mowy o tym, żeby skorzystać z którejkolwiek z opisywanych wyżej możliwości. Jeśli zatem zainstalujemy aplikację (a wraz z nią wszystkie ładowane przez nią biblioteki) w katalogu, który zagwarantuje nam, że długości ścieżek plików przekroczą MAX_PATH, to oczywiście nici z tego i dostaniemy piękny FileLoadException. Jest jeszcze gorzej - nawet jeśli aplikacja nie korzysta z żadnych referencji poza systemowymi, to jeśli ścieżka do pliku konfiguracji (i wcale nie jest ważne, że go nie ma ;)) będzie dłuższa niż MAX_PATH, to dostaniemy "brak dalszych plików" :). Jednym słowem - nie mamy możliwości bezpośredniego załadowania z shella aplikacji .NET znajdującej się 'gdzieś tam, hen daleko'.

Zupełnie inaczej wygląda sytuacja w przypadku dynamicznego ładowania bibliotek w czasie pracy aplikacji. Weźmy dla przykładu taką bibliotekę:

using System;
namespace pl.net.zine.Articles
{
 public class TestLib
 {
    public static void Test()
    {
     Console.WriteLine("Hello from TestLib!");
    }
 }
}

i nazwijmy ją TestLib.dll. Następnie weźmy następujący kawałek kodu:

using System;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Reflection;
namespace pl.net.zine.Articles
{
 public class ADSLoadLibrary
 {
    static string fileName = @"\\?\c:\temp\tests\TestLib.dll";
    static string fileNameStream = @"\\?\c:\temp\tests\articles.exe:TestLib.dll";
    static string fileNameLong = 
@"\\?\c:\temp\tests\Test_4_Long_012345678901234567890123456789012345678901234567
89012345678901234567890123456789012345678901234567890123456789012345678901234567
89012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456TestLib.dll"
;
    public static void Main(string[] args)
    {
     Assembly ass = LoadAssembly(fileName);
     object o = ass.CreateInstance("pl.net.zine.Articles.TestLib");
     MethodInfo m = ass.GetType("pl.net.zine.Articles.TestLib").GetMethod("Test");
     object ret = m.Invoke(o, new object[]{});
    }
    public static Assembly LoadAssembly(string fileName)
    {
     Assembly ass = null;
     byte[] data = null;
     using (SafeFileHandle fileHandle = Win32.CreateFile(fileName, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
     {
       using (FileStream stream = new FileStream(fileHandle, FileAccess.Read))
       {
         using (BinaryReader reader = new BinaryReader(stream))
         {
           data = reader.ReadBytes((int)reader.BaseStream.Length);
         }
       }
     }
     if (data != null)
       ass = Assembly.Load(data);
     return ass;
    }
 }
}

w którym korzystamy z PInvoke do załadowania pliku oraz mechanizmu refleksji do wykonania kodu z załadowanej biblioteki.
W powyższym kodzie zakładam, że plik TestLib.dll znajduje się w katalogu c:\temp\tests, ale dla ćwiczenia proponuję spróbować zapisać plik z długą ścieżką oraz jako alternatywny strumień pliku (przykłady takich nazw są zapisane w kodzie jako fileNameStream oraz fileNameLong, odpowiednio). Działa? :) No cóż, to chyba dobra wiadomość dla tych, którzy chcieliby ukryć swój kod przed widokiem - np. jako alternatywny strumień, powiedzmy jako c:\windows\notepad.exe:testlib.dll, jak widać nie ma bowiem najmniejszego problemu z załadowaniem takiego czegoś do przestrzeni adresowej procesu.

Na koniec krótka zagadka.

W ramach klasy System.IO.FileStream jest kilka internalowych konstruktorów, z których jeden ma następującą sygnaturę:

internal FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, string msgPath, bool bFromProxy, bool useLongPath)

i w ramach normalizacji ścieżki używa stałej System.IO.Path.MaxLongPath = 32000 zamiast System.IO.Path.MaxPath = 260 (obie mają dostęp internal). Która klasa korzysta z tego konstruktora i jaki ma ona związek z c:\Documents And Settings\, czyli ścieżkami o których wyżej pisałem? :)

Opublikowane 12 maja 2011 15:28 przez mgrzeg

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

MSM said:

Jak zwykle świetny post :) Ale kilka uwag mam:

`A nie wiemy dlatego, ponieważ nie ma żadnego narzędzia w shellu (Eksplorator Windows, cmd), który poinformowałby nas o tym, jakie dany plik ma strumienie.`

Stanę w obronie shella - cmd może nie ma tej opcji, ale jego polecenie - `dir` ma:

Od Visty jeśli się nie mylę (a na win7 na pewno jest) mamy do dyspozycji piękny przełącznik /r ( dir /r ).

Jest jakiś sensowny powód dla którego .NET zabrania używać ADS/długich ścieżek(/zastrzeżonych nazw plików)? Zawsze intuicyjnie spodziewałem się że .Netowe funkcje IO to po prostu wrappery dla funkcji natywnych, a z tego by wynikało że jest inaczej (chyba że przeprowadzane są nienajszczęśliwsze checki dotyczące MAX_PATH które odrzucają poprawne ścieżki i rzucają wyjątek)... (mam nadzieję że w miarę jasno zapytałem, trochę się chyba zamotałem)

maja 12, 2011 17:08
 

mgrzeg said:

@MSM: racja, dir ma taką opcję! :) Co prawda u mnie po

>dir /?

mam w wyniku wszystko, a tam gdzie powinno być /R mam:

 /Q          Wy˜świetla informacje o wˆłaś˜cicielach plików.

 /Q          Wy˜świetla alternatywne strumienie danych pliku.

:)

Ale dzięki, człowiek uczy się całe życie :) Choć w moim przypadku to raczej przywiązanie do streams.exe i spowodowana lenistwem nieznajomość zmian w poleceniach systemowych ;)

Odnośnie powodów stojących za taką, a nie inną decyzją, to polecam lekturę wpisów z blogu teamu BCL, do których dałem link w tekście. Już nie chciałem tego pisać wprost w notce, ale coś mi się zdaje, że wspomniane problemy będą się wlokły za produktami Microsoftu (w tym i .NET) jeszcze baaardzo długo. Nie sądzę, żeby zdecydowali się szybko na zmiany w API Win32, bo przecież 'jest cała masa kodu 3rd party, który trafi szlag', a przecież zawsze można przeorganizować strukturę katalogów, porobić trochę linków (mklink /d i mklink /j) i wszystko będzie śmigać :).

Z tego, co można wyczytać, 'jak tylko nastąpią zmiany w API Win32, to .NET będzie na to gotowy' i pomimo obietnic (z kwietnia 2007 r.!):

"We've been looking into supporting long paths in the next release of the framework, but that's a couple years away"

nic się nie zmieniło.

m.

maja 12, 2011 17:48
 

dotnetomaniak.pl said:

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

maja 13, 2011 01:16
 

omeg said:

Pamiętam kiedy jakiś czas temu stworzyłem takie scieżki długości zblożonej do 32k znaków na jakimś serwerze... Oczywiście oprogramowanie do backupów się wykładało i admin dzwonił spanikowany. ;)

Inna ciekawa bestia to sparse files - testowałem zachowanie różnych aplikacji proszonych o wczytanie pliku o rozmiarze 16TB, różowo nie było. Najlepszy był Word - "W obszarze pliku sparse.txt wykryto poważny błąd dysku." ;) Więcej: http://omeg.pl/dump/sparse/

A jeśli dorzucimy jeszcze zapętlone linki NTFS... ;)

maja 13, 2011 09:35

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

W oparciu o Community Server (Personal Edition), Telligent Systems