/* * ReactOS kernel * Copyright (C) 2002, 2004 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* $Id$ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: services/fs/cdfs/misc.c * PURPOSE: CDROM (ISO 9660) filesystem driver * PROGRAMMER: Eric Kohl * UPDATE HISTORY: */ /* INCLUDES *****************************************************************/ #include "cdfs.h" #define NDEBUG #include /* FUNCTIONS ****************************************************************/ VOID CdfsSwapString(PWCHAR Out, PUCHAR In, ULONG Count) { PUCHAR t = (PUCHAR)Out; ULONG i; for (i = 0; i < Count; i += 2) { t[i] = In[i+1]; t[i+1] = In[i]; if (t[i+1] == 0 && t[i] == ';') break; } if ((i>2)&&(t[i-2] == '.')) { t[i-2] = 0; t[i-1] = 0; } t[i] = 0; t[i+1] = 0; } VOID CdfsDateTimeToSystemTime(PFCB Fcb, PLARGE_INTEGER SystemTime) { TIME_FIELDS TimeFields; LARGE_INTEGER LocalTime; TimeFields.Milliseconds = 0; TimeFields.Second = Fcb->Entry.Second; TimeFields.Minute = Fcb->Entry.Minute; TimeFields.Hour = Fcb->Entry.Hour; TimeFields.Day = Fcb->Entry.Day; TimeFields.Month = Fcb->Entry.Month; TimeFields.Year = Fcb->Entry.Year + 1900; RtlTimeFieldsToTime(&TimeFields, &LocalTime); ExLocalTimeToSystemTime(&LocalTime, SystemTime); } VOID CdfsFileFlagsToAttributes(PFCB Fcb, PULONG FileAttributes) { /* FIXME: Fix attributes */ *FileAttributes = // FILE_ATTRIBUTE_READONLY | ((Fcb->Entry.FileFlags & FILE_FLAG_HIDDEN) ? FILE_ATTRIBUTE_HIDDEN : 0) | ((Fcb->Entry.FileFlags & FILE_FLAG_DIRECTORY) ? FILE_ATTRIBUTE_DIRECTORY : 0) | ((Fcb->Entry.FileFlags & FILE_FLAG_SYSTEM) ? FILE_ATTRIBUTE_SYSTEM : 0) | ((Fcb->Entry.FileFlags & FILE_FLAG_READONLY) ? FILE_ATTRIBUTE_READONLY : 0); } BOOLEAN CdfsIsNameLegalDOS8Dot3(IN UNICODE_STRING FileName ) { ULONG i; STRING DbcsName; CHAR DbcsNameBuffer[12]; /* 8dot3 filename is max 12 length */ if (FileName.Length / sizeof(WCHAR) > 12) { return FALSE; } for (i = 0; i < FileName.Length / sizeof(WCHAR) ; i++) { /* Don't allow spaces in FileName */ if (FileName.Buffer[i] == L' ') return FALSE; } /* If FileName is finishing with a dot, remove it */ if (FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == '.') { FileName.Length -= sizeof(WCHAR); } /* Finally, convert the string to call the FsRtl function */ DbcsName.MaximumLength = 12; DbcsName.Buffer = DbcsNameBuffer; if (!NT_SUCCESS(RtlUnicodeStringToCountedOemString(&DbcsName, &FileName, FALSE ))) { return FALSE; } return FsRtlIsFatDbcsLegal(DbcsName, FALSE, FALSE, FALSE); } VOID CdfsShortNameCacheGet (PFCB DirectoryFcb, PLARGE_INTEGER StreamOffset, PUNICODE_STRING LongName, PUNICODE_STRING ShortName) { PLIST_ENTRY Entry; PCDFS_SHORT_NAME ShortNameEntry; GENERATE_NAME_CONTEXT Context = { 0 }; DPRINT("CdfsShortNameCacheGet(%I64u,%wZ)\n", StreamOffset->QuadPart, LongName); /* Get the name list resource */ ExAcquireResourceExclusiveLite(&DirectoryFcb->NameListResource, TRUE); /* Try to find the name in our cache */ for (Entry = DirectoryFcb->ShortNameList.Flink; Entry != &DirectoryFcb->ShortNameList; Entry = Entry->Flink) { ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry); if (ShortNameEntry->StreamOffset.QuadPart == StreamOffset->QuadPart) { /* Cache hit */ RtlCopyMemory (ShortName->Buffer, ShortNameEntry->Name.Buffer, ShortNameEntry->Name.Length); ShortName->Length = ShortNameEntry->Name.Length; ExReleaseResourceLite(&DirectoryFcb->NameListResource); DPRINT("Yield short name %wZ from cache\n", ShortName); return; } } /* Cache miss */ if (!CdfsIsNameLegalDOS8Dot3(*LongName)) { RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName); } else { /* copy short name */ RtlUpcaseUnicodeString (ShortName, LongName, FALSE); } DPRINT("Initial Guess %wZ\n", ShortName); /* Make it unique by scanning the cache and bumping */ /* Note that incrementing the ambiguous name is enough, since we add new * entries at the tail. We'll scan over all collisions. */ /* XXX could perform better. */ for (Entry = DirectoryFcb->ShortNameList.Flink; Entry != &DirectoryFcb->ShortNameList; Entry = Entry->Flink) { ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry); if (RtlCompareUnicodeString (ShortName, &ShortNameEntry->Name, TRUE) == 0) /* Match */ { RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName); DPRINT("Collide; try %wZ\n", ShortName); } } /* We've scanned over all entries and now have a unique one. Cache it. */ ShortNameEntry = ExAllocatePoolWithTag(PagedPool, sizeof(CDFS_SHORT_NAME), TAG_FCB); if (!ShortNameEntry) { /* We couldn't cache it, but we can return it. We run the risk of * generating a non-unique name later. */ ExReleaseResourceLite(&DirectoryFcb->NameListResource); DPRINT1("Couldn't cache potentially clashing 8.3 name %wZ\n", ShortName); return; } ShortNameEntry->StreamOffset = *StreamOffset; ShortNameEntry->Name.Buffer = ShortNameEntry->NameBuffer; ShortNameEntry->Name.Length = ShortName->Length; ShortNameEntry->Name.MaximumLength = sizeof(ShortNameEntry->NameBuffer); RtlCopyMemory (ShortNameEntry->NameBuffer, ShortName->Buffer, ShortName->Length); InsertTailList(&DirectoryFcb->ShortNameList, &ShortNameEntry->Entry); ExReleaseResourceLite(&DirectoryFcb->NameListResource); DPRINT("Returning short name %wZ for long name %wZ\n", ShortName, LongName); } /* EOF */