Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1862 lines
62 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
name.c
Abstract:
This module implements OS/2 V2.0 name processing
Author:
Therese Stowell (thereses) 26-Sep-1989
Revision History:
Yaron Shamir (YaronS) 7-June-91
Move Named Pipes from \OS2SS\DRIVES\NamedPipe to
\OS2SS\PIPE
Yaron Shamir (YaronS) 26-Aug-91
Support UNC. Link to \OS2SS\UNC
Beni Lavi (BeniL) 4-Mar-92
Support MAILSLOT. Link to \OS2SS\MAILSLOT
--*/
#define INCL_OS2V20_MEMORY
#define INCL_OS2V20_QUEUES
#define INCL_OS2V20_SEMAPHORES
#define INCL_OS2V20_ERRORS
#include "os2dll.h"
#ifdef DBCS
// MSKK Oct.20.1993 V-AkihiS
#include "conrqust.h"
#include "os2win.h"
#endif
APIRET
VerifyDriveExists(
IN ULONG DiskNumber
);
#ifdef DBCS
// MSKK Oct.27.1993 V-Akihis
CHAR Od2InvalidCharacters[]= { '"',
'/',
(CHAR)OBJ_NAME_PATH_SEPARATOR,
':',
'<',
'|',
'>',
'\0'
};
CHAR Od2FatInvalidCharacters[]= { '"',
'/',
(CHAR)OBJ_NAME_PATH_SEPARATOR,
'[',
']',
':',
'<',
'|',
'>',
'+',
'=',
';',
',',
'\0'
};
#else
CHAR Od2InvalidCharacters[]= { '"',
'/',
(CHAR)OBJ_NAME_PATH_SEPARATOR,
'[',
']',
':',
'<',
'|',
'>',
'+',
'=',
';',
',',
'\0'
};
#endif
//character devices:
// emulate existence of "default" devices
// maintain list of installed devices. symbolic link to real name.
//
//question: what if device exists not in \DEV\ directory and process opens it?
//
//name processing
//
// - map all /s to \s
// - process . and ..s
// - prepend current directory to relative paths
// - remove trailing blanks and dots
// - detect UNC. compact multiple leading \s
// - compact multiple \s
// - detect pipe. disallow leading d:
// - detect installed and "default" devices
// - detect illegal chars?
//
//
// detect device (in list of default/installed devices)
// detect UNC (multiple leading \\s)
// detect PIPE (leading \PIPE\)
// if !(UNC || PIPE) && relative path
// prepend current directory
// process . and ..s
// map all /s to \s
// remove trailing blanks and dots
//
//
BOOLEAN
TestForPipe(
IN PSZ name
)
/*++
Routine Description:
This routine determines whether a filename is a pipe name.
Arguments:
name - filename to test
Return Value:
BOOLEAN - TRUE if the filename is a pipe name. FALSE
otherwise
--*/
{
while (ISSLASH(*name)) { // eat any extra slashes
name++;
}
if (_strnicmp(name,"pipe",4)) {
return FALSE;
}
if (!(ISSLASH(*(name+4)))) {
return FALSE;
}
return TRUE;
}
BOOLEAN
TestForMailslot(
IN PSZ name
)
/*++
Routine Description:
This routine determines whether a filename is a mailslot name.
Arguments:
name - filename to test
Return Value:
BOOLEAN - TRUE if the filename is a mailslot name. FALSE
otherwise
--*/
{
while (ISSLASH(*name)) { // eat any extra slashes
name++;
}
if (_strnicmp(name,"mailslot",8)) {
return FALSE;
}
if (!(ISSLASH(*(name+8)))) {
return FALSE;
}
return TRUE;
}
PSZ
FindLastComponent(
IN PSZ String
)
/*++
Routine Description:
This routine finds the last component in a string. the string has not
been canonicalized.
Arguments:
String - string to examine
Return Value:
pointer to last component
--*/
{
PSZ LastComponent;
#ifdef DBCS
// MSKK Apr.11.1993 V-AkihiS
if ((!Ow2NlsIsDBCSLeadByte(String[COLON-1], SesGrp->DosCP)) && String[COLON] == ':') {
#else
if (String[COLON] == ':') {
#endif
LastComponent = String+FIRST_SLASH;
}
else {
LastComponent = String;
}
while (*String) {
#ifdef DBCS
// MSKK Apr.11.1993 V-AkihiS
if (Ow2NlsIsDBCSLeadByte(*String, SesGrp->DosCP)) {
String++;
if (*String) {
String++;
}
}
else {
if (ISSLASH(*String))
LastComponent = String;
String++;
}
#else
if (ISSLASH(*String))
LastComponent = String;
String++; // BUGBUG make dbcs-correct
#endif
}
if (ISSLASH(*LastComponent))
return LastComponent+1;
else
return LastComponent;
}
/*
;*** DOSICANONICALIZE - Convert a path name into a standard format
;
; INTERNAL ONLY API. Used by a couple of dynamic link libraries.
; The worker routine does NO error checking or memory protection
; checks. It is possible to general an internal error if used
; incorrectly. DO NOT PUBLISH.
;
; INVOKE PUSH@ ASCIIZ Source (2 words)
; PUSH@ ASCIIZ Dest (2 words)
; PUSH WORD BackupOffset (1 word)
; PUSH WORD DestEnd (1 word)
; PUSH WORD Flags (1 word)
; call DOSICANONICALIZE
;
; RETURN (ax) = error code
;
*/
void DosICanonicalize(PCHAR Source, PCHAR Dest, USHORT BackupOffset,
USHORT DestEnd, USHORT Flags)
{
PCHAR SourcePtr,DestPtr;
char Buffer[256];
STRING tmpstr;
tmpstr.Length=0;
tmpstr.MaximumLength=256;
tmpstr.Buffer=Buffer;
SourcePtr = Source + BackupOffset;
DestPtr = Dest + BackupOffset;
Od2Canonicalize(
SourcePtr,
CANONICALIZE_FILE_DEV_OR_PIPE,
&tmpstr,
NULL, // OUT PHANDLE DirectoryHandle OPTIONAL,
NULL, // OUT PULONG ParseFlags OPTIONAL,
NULL // OUT PULONG FileType OPTIONAL
);
strncpy(DestPtr,tmpstr.Buffer,DestEnd-BackupOffset);
}
APIRET
Od2Canonicalize(
IN PSZ Name,
IN ULONG ExpectedType,
OUT PSTRING CanonicalString,
OUT PHANDLE DirectoryHandle OPTIONAL,
OUT PULONG ParseFlags OPTIONAL,
OUT PULONG FileType OPTIONAL
)
/*++
Routine Description:
This routine canonicalizes a filename and determines its type, based
on naming conventions.
Arguments:
Name - Supplies a pointer to a null terminated path name that will be
parsed.
ExpectedType - Supplies the expected type of the path string that will be
parsed. Any of the following:
CANONICALIZE_FILE_DEV_OR_PIPE - the input path must refer to either
a local file or device name, a UNC file name, or a named pipe.
CANONICALIZE_FILE_OR_DEV - the input path must refer to either
a local file or device name, or a UNC file name. Named pipes
are treated as local files. Used by DosMove for renaming
files that begin with \pipe
CANONICALIZE_SHARED_MEMORY - the input path must refer to a shared
memory section. This means it must begin with \sharemem\
CANONICALIZE_SEMAPHORE - the input path must refer to a 32-bit
semaphore name. This means it must begin with \sem32\
CANONICALIZE_QUEUE - the input path must refer to a 32-bit queue
name. This means it must begin with \queues\
CANONICALIZE_MAILSLOT - the input path must refer to a mailslot
name. This means it must begin with \mailslot\ or \\*\mailslot\
CanonicalString - Supplies a pointer to a counted string that will be
set to point to a buffer containing the result of canonicalizing
the input path string. The space for the buffer is allocated
from the heap specified by the OutputHeap parameter or Od2Heap
if that parameter is not specified.
DirectoryHandle - Supplies an optional pointer to a place to store an
NT Directory handle if the output string can be expressed as a
relative path string, relative to a current directory. If this
parameter is not specified or if the returned directory handle is
NULL then the canonical path string placed in OutputString will
be a fully qualified path string.
ParseFlags - Supplies an optional pointer to flags will be used to
return information about the results of the parse.
This parameter is ignored if the ExpectedType parameter is
anything other than CANONICALIZE_FILE_DEV_OR_PIPE or
CANONICALIZE_FILE_OR_DEV.
Flag values set by this function:
CANONICALIZE_META_CHARS_FOUND - the path name contains either an
asterisk (*) and/or question marks (?) in the last component
of the output string.
CANONICALIZE_IS_ROOT_DIRECTORY - the output string specifies a root
directory (e.g. D:\).
FileType - Supplies an optional pointer to a place to store the type
of object the canonical path string describes. Possible values
are:
FILE_TYPE_FILE
FILE_TYPE_NMPIPE
FILE_TYPE_DEV
FILE_TYPE_PSDEV
FILE_TYPE_MAILSLOT
This parameter is ignored if the ExpectedType parameter is
anything other than CANONICALIZE_FILE_DEV_OR_PIPE,
CANONICALIZE_FILE_OR_DEV or CANONICALIZE_MAILSLOT.
Return Value:
OS/2 Error Code
Return Value:
ERROR_FILE_NOT_FOUND - the filename is invalid.
Note:
This routine allocates a buffer to hold the canonicalized name. it
is the caller's responsibility to free this buffer.
Pseudocode:
determine expected prefix
if (file_pipe_or_dev)
detect UNC - insert correct prefix
detect devices - insert correct prefix
insert drive letter if needed - insert correct prefix
insert current directory if needed
else
check for ///prefix/
insert correct prefix
copy string, removing . and .., checking for illegal characters,
detecting metacharacters
Routine Description:
This function performs the OS/2 V2.0 Path Name canonicalization
function. It takes as input a pointer to a null terminated string
that is considered unprobed, along with flags that specify optional
behavior while parsing the path string. The output of this function
is a canonical path string that is in NT format. The OS/2 Subsystem
creates the following objects in the NT Object Name Space in order
to support the output of this function:
\OS2SS object directory
\OS2SS\DRIVES object directory
\OS2SS\DRIVES\A: symbolic link => \Device\Floppy0
\OS2SS\DRIVES\C: symbolic link => \Device\Harddisk0\Partition1
\OS2SS\DRIVES\D: symbolic link => \Device\Harddisk1\Partition1
\OS2SS\PIPE symbolic link => \DosDevices\PIPE
\OS2SS\UNC symbolic link => \DosDevices\UNC
\OS2SS\DEVICES object directory
\OS2SS\DEVICES\NUL symbolic link => @0
\OS2SS\DEVICES\CON symbolic link => @1
\OS2SS\DEVICES\AUX symbolic link => @2
\OS2SS\DEVICES\COM1 symbolic link => @2.0
\OS2SS\DEVICES\COM2 symbolic link => @2.1
\OS2SS\DEVICES\COM3 symbolic link => @2.2
\OS2SS\DEVICES\COM4 symbolic link => @2.3
\OS2SS\DEVICES\PRN symbolic link => @3
\OS2SS\DEVICES\LPT1 symbolic link => @3.0
\OS2SS\DEVICES\LPT2 symbolic link => @3.1
\OS2SS\DEVICES\LPT3 symbolic link => @3.2
\OS2SS\DEVICES\KBD$ symbolic link => @4
\OS2SS\DEVICES\MOUSE$ symbolic link => @5
\OS2SS\DEVICES\CLOCK$ symbolic link => @6
\OS2SS\DEVICES\SCREEN$ symbolic link => @7
\OS2SS\DEVICES\POINTER$ symbolic link => @8
\OS2SS\QUEUES object directory
\OS2SS\SHAREMEM object directory
\OS2SS\SEMAPHORES object directory
The actual drive letters that will be defined in the \OS2SS\DRIVES
object directory actually depend upon the hardware configuration you
are running on. The above is an example for a particular machine.
Also notice that the GlobalDFS link actually is the same as the
LocalDFS link, namely the redirector. This will be true until we
implement a real name service file system.
Listed below are some examples of OS/2 path strings and the desired
NT path string. These examples assume the current drive and
directory for the OS/2 application are C:\Os2\Dll
OS/2 Path NT Path
pmwin.dll \OS2SS\DRIVES\C:\Os2\Dll\pmwin.dll
c:pmwin.dll \OS2SS\DRIVES\C:\Os2\Dll\pmwin.dll
C:\os2\dll\pmwin.dll \OS2SS\DRIVES\C:\os2\dll\pmwin.dll
c:\DLL\..\pmwin.dll \OS2SS\DRIVES\C:\Os2\DLL\pmwin.dll
c:\OS2\.\DLL\..\..\pmwin.dll \OS2SS\DRIVES\C:\OS2\DLL\pmwin.dll
\\mach\shr\a\b\c \OS2SS\DRIVES\LocalDFS\mach\shr\a\b\c
\\\mach\shr\a\b\c \OS2SS\DRIVES\GlobalDFS\mach\shr\a\b\c
\pipe\a\b\c\pipe.C \OS2SS\DRIVES\PIPE/a/b/c/pipe.C
con @1 - internal pseudo device
c:clock$ @6 - internal pseudo device
\a\b\c\screen$ @7 - internal pseudo device
\queUES\a\b\c\..\..\..\que. \OS2SS\QUEUES\QUE
\shaREmem\a\b\c\.\mem.c \OS2SS\SHAREDMEMORY\A/B/C/MEM.C
\sem32\a\b\c\..\sem.b \OS2SS\SEMAPHORES\A/B/SEM.B
Notice that for the last three examples, the output string contains
forward slashes instead of the normal backslash path separator.
This allows the names to be stored in the NT Object Name Space
without having to create the implied directory structure. The
NamedPipes example also does this, although this can be changed
if the NamedPipe File System is integrated into the NT Pinball File
System.
Also for the first five examples, since each NT path begins with the
current drive and directory, the output path returned by this function
will be just the file name, pmwin.dll and the NT handle that points
to the current directory of C: (i.e. \OS2SS\DRIVES\C:\Os2\Dll). This
allows cheaper relative opens to be used for most opens of files.
What follows is a description of how this function parses the input
path string:
- first allocates a buffer from Od2Heap. The buffer is large
enough to contain the longest possible OS/2 path string, plus
the space implied by the length of the input path string.
- figures out what prefix to use based on expected file type.
- if a file system path is expected (file, pipe, unc, or device),
determines what type of path is input. the correct constant prefix is
copied to the beginning of the buffer. A UNC path is first detected
by checking for two leading slashes. If "\\" is found,
"\OS2SS\UNC" is copied to the buffer.
Then the server name is copied to the buffer. The end of the server name is the backup limit for
'..' processing. Then a pipe path is checked for by looking for the
"PIPE" prefix at the beginning of the path. If it is found,
"\OS2SS\PIPE" is copied into the buffer. Also
set a flag so that all backslash path separator characters in the
output string will be mapped to forward slashes. The end of the
\pipe\ prefix is the backup limit for ".." processing. If the
path is not UNC or pipe, a device path is checked for by doing the
following:
lookup the trailing component of the output path string in
the \OS2SS\DEVICES directory as a symbolic link. If found
then extract the target string of the symbolic link and
parse it as follows:
@n[.m] - specifies a pseudo-device that is builtin to
the OS/2 Emulation subsystem. n is a decimal, zero
based index into the pseudo-device table. The ".m" is
optional and if present, m is a decimal, zero based
number that represents the unit number. For devices
with unit numbers, if m is not present a default unit
number should be used (zero in most cases). In either
case the type returned is FILE_TYPE_PSDEV. The caller
should key off of this type to determine if it should
parse the contents of the canonical name string.
NT Path String - specifies a fully qualified name of a
physical device. The type returned is FILE_TYPE_DEV
If the path is not a device, it is assumed to be a file. The
drive letter and current directory are copied to buffer if needed.
The buffer will contain \OS2SS\DRIVES\d:\currentdir at this point.
The slash after the drive letter is the backup limit for ".."
processing.
The filetype is set according to the type of path found.
- if a non-file system path is expected, the expected prefix is
verified and the constant and expected prefixes are copied to the
buffer.
if the ExpectedType parameter is CANONICALIZE_QUEUES, then see
if the beginning of the input path string matches \QUEUES\
ignoring case. If they do not match, then the
ERROR_PATH_NOT_FOUND error code is returned from this
function. Also set a flag so that all backslash path
separator characters in the output string will be mapped
to forward slashes. If it does match then \OS2SS\QUEUES\QUEUES
is copied to the buffer. The end of the second QUEUES prefix
is the backup limit for ".." processing.
if the ExpectedType parameter is CANONICALIZE_SEMAPHORE, then
see if the beginning of the input path string matches \SEM32\
ignoring case. If they do not match, then the
ERROR_PATH_NOT_FOUND error code is returned from this
function. Also set a flag so that all backslash path
separator characters in the output string will be mapped to
forward slashes. If it does match then \OS2SS\SEMAPHORES\SEM32
is copied to the buffer. The end of the SEM32 prefix
is the backup limit for ".." processing.
if the ExpectedType parameter is CANONICALIZE_SHARED_MEMORY,
then see if the beginning of the input path string matches
\SHAREMEM\ ignoring case. If they do not match, then the
ERROR_PATH_NOT_FOUND error code is returned from this
function. Also set a flag so that all backslash path
separator characters in the output string will be mapped
to forward slashes. If it does match then
\OS2SS\SHAREDMEMORY\SHAREMEM is copied to the buffer. The end of
the SHAREMEM prefix is the backup limit for ".." processing.
- copies the unprobed remainder of the input path string to the
allocated buffer, performing the following logic for each character:
- if an access violation exception occurs when fetching a
character from the input path string, the ERROR_INVALID_ADDRESS
error code is returned as the value of this function.
- forward slash (/) path separators into are converted to the
NT path separator character (OBJ_NAME_PATH_SEPARATOR).
- meta characters (* and ?) are detected. If found before a
path separator then the ERROR_PATH_NOT_FOUND error code is
returned as the value of this function.
- if the ExpectedType parameter is neither of
CANONICALIZE_FILE_DEV_OR_PIPE or CANONICALIZE_FILE_OR_DEV,
then lower case letters are converted to upper case when
they are copied to the output buffer.
- if the ExpectedType parameter is neither of
CANONICALIZE_FILE_DEV_OR_PIPE or CANONICALIZE_FILE_OR_DEV and
meta characters are detected then the ERROR_PATH_NOT_FOUND error
code is returned as the value of this function.
- if the input string begins with a character followed by a
colon (:), then map the drive letter to upper case.
- sequences one or more adjacent backslashes
(OBJ_NAME_PATH_SEPARATOR) are converted to a single backslash.
- process '.' and '..' path components. '.' are removed. '..'
components cause the immediately previous component to be
removed. i.e. d:\foo\..\bar -> d:\bar. An error is returned
if there is no component to remove.
- If specified by the earlier logic, the trailing path separator
of each component is set to be a forward slash after the copy.
This basically maps any multiple component path string into a
single component name.
- After copying each path component, remove trailing blanks
and periods. If the last path component contained meta
characters then put a trailing period at the end of the last
component if it does contained one or more trailing periods
already.
- when unicode strings are put into the system, the code page to
unicode conversion will happen in this step.
- return the type of path via the FileType parameter, which
must be specified if the ExpectedType parameter is
CANONICALIZE_FILE_DEV_OR_PIPE or CANONICALIZE_FILE_OR_DEV.
- if this function returns an error code instead of NO_ERROR then
free the output buffer that was allocated. Otherwise set the
Length and Maximum length fields in the counted string pointed
to by the OutputString parameter.
--*/
{
PSZ Dest,
Src,
LastComponent,
BackUpLimit;
CHAR c;
ULONG Drive;
PSTRING CurrentDirectoryString;
HANDLE CurrentDirectoryHandle;
ULONG CurrentDirectoryLength;
PSZ NameBuffer;
ULONG NameBufferLength;
APIRET RetCode;
PSZ PipePrefix;
PSZ MailslotPrefix;
PSZ UNCPrefix;
PSZ ExpectedPrefix;
PSZ ConstantPrefix;
PSZ Os2Name;
int RemoveBlanksAndDots;
ULONG ExpectedPrefixLength;
BOOLEAN MetaCharactersAllowed;
BOOLEAN PreserveCase;
BOOLEAN MapToRootName;
BOOLEAN ValidateChars;
ULONG OutputFlags;
ULONG OutputType;
NTSTATUS Status;
HANDLE DeviceHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
STRING DeviceName;
UNICODE_STRING DeviceName_U;
WCHAR DeviceNameBuffer[ CCHMAXPATH ];
#ifdef DBCS
// Oct.27.1993 V-AkihiS
CHAR *InvalidCharacters = Od2InvalidCharacters;
#endif
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "Od2Canonicalize: entering with path %s\n", Name);
}
#endif
PipePrefix = NULL;
MailslotPrefix = NULL;
UNCPrefix = NULL;
PreserveCase = FALSE;
MetaCharactersAllowed = FALSE;
MapToRootName = TRUE;
ValidateChars = TRUE;
OutputType = 0xFFFFFFFF;
OutputFlags = 0;
CurrentDirectoryString = NULL;
CurrentDirectoryHandle = NULL;
Os2Name = NULL;
RetCode = NO_ERROR;
//
// determine the expected and constant prefixes of the path,
// where the constant prefix is the
//
switch( ExpectedType ) {
case CANONICALIZE_FILE_DEV_OR_PIPE:
case CANONICALIZE_FILE_OR_DEV:
case CANONICALIZE_MAILSLOT:
PipePrefix = "\\PIPE\\";
UNCPrefix = "\\UNC\\";
ExpectedPrefix = NULL;
ConstantPrefix = "\\OS2SS\\DRIVES";
PreserveCase = TRUE;
MetaCharactersAllowed = TRUE;
MapToRootName = FALSE;
OutputType = FILE_TYPE_FILE;
MailslotPrefix = "\\MAILSLOT\\";
break;
case CANONICALIZE_SHARED_MEMORY:
ExpectedPrefix = DA_SHAREMEM_NAMEPREFIX;
ConstantPrefix = "\\OS2SS\\SHAREMEM";
break;
case CANONICALIZE_SEMAPHORE:
ExpectedPrefix = DC_SEM_NAMEPREFIX;
ConstantPrefix = "\\OS2SS\\SEMAPHORES";
break;
case CANONICALIZE_QUEUE:
ExpectedPrefix = DC_QUEUES_NAMEPREFIX;
ConstantPrefix = "\\OS2SS\\QUEUES";
break;
default:
return( ERROR_INVALID_FUNCTION );
}
if (ExpectedPrefix != NULL) {
ExpectedPrefixLength = strlen( ExpectedPrefix );
}
try {
if (*Name == '\0')
return ERROR_FILE_NOT_FOUND;
if (*Name == ' ' && *(Name+1) == '\0')
return ERROR_PATH_NOT_FOUND;
//
// initialize DirectoryHandle to indicate full path returned.
//
if (DirectoryHandle != NULL) {
*DirectoryHandle = NULL;
}
//
// allocate name buffer. make it big enough that we can't overrun the
// end of it.
//
NameBufferLength = CCHMAXPATH + strlen(Name)+ CANONICALIZE_MAX_PREFIX_LENGTH;
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (( NameBuffer = RtlAllocateHeap(Od2Heap,0,NameBufferLength)) == NULL )
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
Dest = NameBuffer;
Src = Name;
//
// if we're doing a canonicalization for an IO system API (a file, device,
// UNC, or pipe name is expected), we
// detect UNC - insert correct prefix
// detect devices - insert correct prefix
// insert drive letter if needed - insert correct prefix
// insert current directory if needed
//
if ((ExpectedType == CANONICALIZE_FILE_DEV_OR_PIPE) ||
(ExpectedType == CANONICALIZE_FILE_OR_DEV) ||
(ExpectedType == CANONICALIZE_MAILSLOT)
) {
//
// detect UNC and pipe names
//
// NOTES on UNC naming conventions:
//
// Two or three leading slashes are OK, and unmodified.
//
// Four or more leading slashes are compressed to three
// leading slashes.
//
// Any number of slashes as a separator, in a local or UNC
// path, are compressed to a single slash.
//
// The \\ is a short hand for the 'current name space' whereas
// three slashes are the root of the world-wide name space.
//
//
CurrentDirectoryString = NULL;
if (ISSLASH(Src[0])) {
if (ISSLASH(Src[1])) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "processing UNC name\n");
}
#endif
OutputType = FILE_TYPE_UNC;
//
// copy constant prefix to buffer
//
ConstantPrefix = "\\OS2SS";
while (*Dest++ = *ConstantPrefix++)
;
Dest--;
Os2Name = Dest; // Os2Name points to beginning of OS/2 name
while (*Dest++ = *UNCPrefix++)
;
Dest--;
Src += 2; // for the two slashes
if (ISSLASH(*Src)) {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit; // go free buffer(s) and return error
}
Os2Name = Dest-1; // Os2Name points to beginning of OS/2 name
/*
path is \OS2SS\UNC\
copy the server name.
*/
while (!ISPATHSEP(*Src)) {
if ((*Src == '?') ||
((*Src == '*') && (ExpectedType != CANONICALIZE_MAILSLOT))) {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit;
}
#ifdef JAPAN
// MSKK Feb.18.1993 V-AkihiS
if (Ow2NlsIsDBCSLeadByte(*Src, SesGrp->DosCP)) {
*Dest++ = *Src++;
if (*Src) {
//
// Check Trailing byte is valid or not.
//
if ((UCHAR)*Src < 0x40 || (UCHAR)*Src > 0xFC || (UCHAR)*Src == 0x7F) {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit;
} else {
*Dest++ = *Src++;
}
} else {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit;
}
}
else {
if (ValidateChars && ((UCHAR)*Src < (UCHAR)' ' ||
strchr( InvalidCharacters, *Src )
)
) {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit;
}
*Dest++ = *Src++;
}
#else
if (ValidateChars && ((UCHAR)*Src < (UCHAR)' ' ||
strchr( Od2InvalidCharacters, *Src )
)
) {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit;
}
*Dest++ = *Src++;
#endif
}
if (*Src == '\0') {
RetCode = ERROR_BAD_NETPATH;
goto ErrorExit; // go free buffer(s) and return error
}
*Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR; // append '\'
Src++;
while (ISSLASH(*Src))
Src++;
BackUpLimit = Dest; // set up backup pointer. points after server name
/*
at this point, we have a UNC name composed of
\OS2SS\UNC\servername\
^
|
dest
\\\\servername\\\sharepoint
^
|
src
*/
}
else if (TestForPipe(Src)) { // \PIPE\ ?
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "processing pipe name\n");
}
#endif
OutputType = FILE_TYPE_NMPIPE;
//
// this code assumes that pipes are in \OS2SS
// copy \OS2SS\PIPE into buffer
//
//
// we can't use drives for pipes
// (see ..\server\srvname.c)
//
ConstantPrefix = "\\OS2SS";
while (*Dest++ = *ConstantPrefix++)
;
Dest--;
Os2Name = Dest; // Os2Name points to beginning of OS/2 name
while (*Dest++ = *PipePrefix++)
;
Dest--;
/*
update src pointer past \pipe\
*/
while (ISSLASH(*Src)) // eat any extra slashes
Src++;
Src += 5;
while (ISSLASH(*Src)) // eat any extra slashes
Src++;
if (*Src == '\0') {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
ValidateChars = TRUE;
BackUpLimit = Dest; // set up backup pointer. points after "\pipe\"
}
else if (TestForMailslot(Src)) { // \MAILSLOT\ ?
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "processing mailslot name\n");
}
#endif
OutputType = FILE_TYPE_MAILSLOT;
//
// this code assumes that mailslots are in \OS2SS
// copy \OS2SS\MAILSLOT into buffer
//
//
// we can't use drives for maislots
// (see ..\server\srvname.c)
//
ConstantPrefix = "\\OS2SS";
while (*Dest++ = *ConstantPrefix++)
;
Dest--;
Os2Name = Dest; // Os2Name points to beginning of OS/2 name
while (*Dest++ = *MailslotPrefix++)
;
Dest--;
/*
update src pointer past \mailslot\
*/
while (ISSLASH(*Src)) // eat any extra slashes
Src++;
Src += 9;
while (ISSLASH(*Src)) // eat any extra slashes
Src++;
if (*Src == '\0') {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
ValidateChars = TRUE;
BackUpLimit = Dest; // set up backup pointer. points after "\pipe\"
}
}
// haven't detected pipe or UNC
if (OutputType == FILE_TYPE_FILE) {
#ifdef DBCS
// MSKK Oct.27.1993 V-AkihIS
InvalidCharacters = Od2FatInvalidCharacters;
#endif
/*
detect devices here.
device names are recognized as follows:
installed/default devices are allowed in any d:\path
pseudochar devices must match exactly, starting with \DEV\
*/
LastComponent = FindLastComponent(Src);
if (*LastComponent)
{
PWSTR DotPlace;
USHORT NewLen;
//
// Open as a symbolic link, relative to the OS/2 Device Directory in the
// object name space, the last component of the file path.
//
Od2InitMBString( &DeviceName, LastComponent );
//
// UNICODE conversion -
//
RetCode = Od2MBStringToUnicodeString(
&DeviceName_U,
&DeviceName,
TRUE);
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("Od2Canonicalize: no memory for Unicode Conversion\n");
}
#endif
//return RetCode;
goto ErrorExit;
}
for (DotPlace = DeviceName_U.Buffer, NewLen = 0;
NewLen < DeviceName_U.Length;
DotPlace++, NewLen += sizeof(WCHAR)) {
if ((*DotPlace == L'.') || (*DotPlace == L' ')) {
DeviceName_U.Length = NewLen;
break;
}
}
InitializeObjectAttributes( &ObjectAttributes,
&DeviceName_U,
OBJ_CASE_INSENSITIVE,
Od2DeviceDirectory,
NULL
);
Status = NtOpenSymbolicLinkObject( &DeviceHandle,
SYMBOLIC_LINK_QUERY,
&ObjectAttributes
);
RtlFreeUnicodeString (&DeviceName_U);
if (NT_SUCCESS( Status )) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "processing device name\n");
}
#endif
//
// Found a symbolic link in the OS/2 Device Directory whose
// name matches the last component of the file path. Query
// the target string from the symbolic link.
//
DeviceName_U.Length = 0;
DeviceName_U.MaximumLength = sizeof( DeviceNameBuffer );
DeviceName_U.Buffer = DeviceNameBuffer;
Status = NtQuerySymbolicLinkObject( DeviceHandle,
&DeviceName_U,
NULL
);
NtClose(DeviceHandle);
if (NT_SUCCESS( Status )) {
//
// Successfully queried the target string, so copy it as
// is to the output path buffer, obliterating what was there.
// Next determine the file type by examining the first
// character of the target string. @n is a pseudo-device
// builtin to the OS/2 subsystem. Otherwise it is a physical
// NT device path.
//
RetCode = Od2UnicodeStringToMBString( &DeviceName, &DeviceName_U, TRUE );
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("Od2Canonicalize: no memory for Unicode Conversion-2\n");
}
#endif
//return RetCode;
goto ErrorExit;
}
strncpy( Dest,
&DeviceName.Buffer[1],
DeviceName.Length - 1
);
*(Dest + DeviceName.Length - 1) = '\0'; // for debug printing
if (DeviceName.Buffer[0] == '@') {
OutputType = FILE_TYPE_PSDEV;
}
else if (DeviceName.Buffer[0] == '#') {
OutputType = FILE_TYPE_COM;
}
else {
OutputType = FILE_TYPE_DEV;
}
CanonicalString->MaximumLength = (USHORT) NameBufferLength;
CanonicalString->Length = DeviceName.Length - 1;
CanonicalString->Buffer = NameBuffer;
Od2FreeMBString( &DeviceName );
goto ErrorExit;
}
else {
RetCode = ERROR_PATH_NOT_FOUND; // FIX, FIX - Should never happen.
goto ErrorExit;
}
}
}
}
//
// if we didn't detect a device, we have a file. add a drive letter
// and current directory, if necessary.
//
if (OutputType == FILE_TYPE_FILE) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "processing file name\n");
}
#endif
//
// A xxxx\ is not allowed
//
#ifdef DBCS
// MSKK Feb.26.1993 V-AkihiS
{
ULONG i = 0;
BOOLEAN LastSlashFlag = FALSE;
BOOLEAN ColonFlag = FALSE;
//
// Check last charater is '\' and privious character of last
// character is not ':'. If so(i.e. LastSlashFlag is true,
// when exiting while-loop), it is not allowed.
//
while (i < strlen(Name)) {
if (Ow2NlsIsDBCSLeadByte(Name[i], SesGrp->DosCP)) {
LastSlashFlag = ColonFlag = FALSE;
i++;
if (i < strlen(Name)) i ++;
} else {
if (Name[i] == ':') {
LastSlashFlag = FALSE;
ColonFlag = TRUE;
} else if (ISSLASH(Name[i])) {
if (ColonFlag) {
LastSlashFlag = FALSE;
} else {
LastSlashFlag = TRUE;
}
ColonFlag = FALSE;
} else {
LastSlashFlag = ColonFlag = FALSE;
}
i++;
}
}
if ( LastSlashFlag && (strlen(Name) > 1)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "Canonicalize: filename is D:xxx\\, return ERROR_PATH_NOT_FOUND \n");
}
#endif
return(ERROR_PATH_NOT_FOUND);
}
}
#else
if ( ISSLASH(Name[strlen(Name)-1]) && (strlen(Name) > 1 )
&& (Name[strlen(Name)-2] != ':') /* slash root is a fine name */ ) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "Canonicalize: filename is D:xxx\\, return ERROR_PATH_NOT_FOUND \n");
}
#endif
return(ERROR_PATH_NOT_FOUND);
}
#endif
//
// copy the constant prefix.
//
while (*Dest++ = *ConstantPrefix++)
;
Dest--;
*Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
Os2Name = Dest; // Os2Name points to beginning of OS/2 name
#ifdef DBCS
// MSKK Apr.11.1993 V-AkihiS
if (!(*(Src+1) == ':' && !IsDBCSLeadByte(*Src))) { // if no drive letter, get one
#else
if (*(Src+1) != ':') { // if no drive letter, get one
#endif
*Dest++ = CONVERTTOASCII(Od2CurrentDisk);
*Dest++ = ':';
Drive = Od2CurrentDisk;
}
else {
// figure out which zero-based drive to use
if (*Src > 'Z') {
Drive = *Src - 'a';
}
else {
Drive = *Src - 'A';
}
if (RetCode = VerifyDriveExists(Drive+1)){
return(RetCode);
}
*Dest++ = *Src++; // copy drive letter
*Dest++ = *Src++;
if (*Src == '\0') {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
}
//
// Buffer contains \\OS2SS\DRIVES\D:
// ^
// |
// dest
//
// d:\foo
// ^
// |
// src
//
// set up backup pointer
BackUpLimit = Dest; // set up backup pointer. points to first '\'
//
// prepend logondirectory here
//
// if (relative path)
// copy current directory;
// append '\';
// else
// copy first '\';
//
if (!ISSLASH(*Src)) { // if path not absolute
//
// if no current directory, append '\'
//
*Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
RetCode = Od2GetCurrentDirectory(Drive,
&CurrentDirectoryString,
&CurrentDirectoryHandle,
&CurrentDirectoryLength,
FALSE
);
if (RetCode != NO_ERROR) {
goto ErrorExit; // go free buffer(s) and return error
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint("GetCurrentDirectory returned %s\n",CurrentDirectoryString->Buffer);
}
#endif
if (CurrentDirectoryHandle != NULL) { // if not root directory
CurrentDirectoryString->Length -= DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH;
CurrentDirectoryString->Buffer += DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH;
strncpy(Dest,
CurrentDirectoryString->Buffer,
CurrentDirectoryString->Length
);
Dest += CurrentDirectoryString->Length;
*Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
}
}
else { // copy one '\' and eat any others
*Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
Src++;
while (ISSLASH(*Src))
Src++;
}
/*
the buffer contains:
\OS2SS\DRIVES\D:\currentdir\
^
|
dest
d:foo
^
|
src
*/
}
}
//
// we're doing canonicalization for a non IO system API - semaphores,
// queues, or shared memory. we check for the expected prefix and copy
// it to the buffer. there can be any number of slashes anywhere in
// the name. i.e. \\/\SEM32/////foo -> \SEM32\foo.
//
else {
//
// copy constant prefix to buffer
//
while (*Dest++ = *ConstantPrefix++)
;
Dest--;
//
// verify that the expected prefix is there. advance Src past
// all leading slashes.
//
if (ISSLASH(*Src)) {
do {
Src++;
} while (ISSLASH(*Src));
//
// use the strnicmp to compare for the text part of the prefix and
// ISSLASH to compare for the trailing slash.
//
#ifdef DBCS
// MSKK Feb.26.1993 V-AkihiS
{
ULONG i = 0;
BOOLEAN SlashFlag = FALSE;
//
// verify whether the last character of the text part of
// the prefix is slash or not.
//
while (i < ExpectedPrefixLength - 1) {
if (Ow2NlsIsDBCSLeadByte(*(Src+i), SesGrp->DosCP)) {
SlashFlag = FALSE;
i++;
if (i < ExpectedPrefixLength - 1) {
i++;
}
} else {
if (ISSLASH(*(Src+i))) {
SlashFlag = TRUE;
} else {
SlashFlag = FALSE;
}
i++;
}
}
if (_strnicmp( Src, ExpectedPrefix+1, ExpectedPrefixLength-2 ) ||
!SlashFlag) {
RetCode = ERROR_PATH_NOT_FOUND;
}
}
#else
if (_strnicmp( Src, ExpectedPrefix+1 , ExpectedPrefixLength-2 ) ||
!(ISSLASH(*(Src+ExpectedPrefixLength-2)))) {
RetCode = ERROR_PATH_NOT_FOUND;
}
#endif
Os2Name = Dest; // Os2Name points to beginning of OS/2 name
//
// copy the expected prefix. Make sure terminating slash is
// the correct type.
//
while (c = *ExpectedPrefix++) {
if (c == (CHAR)OBJ_NAME_PATH_SEPARATOR && MapToRootName) {
c = '/';
}
*Dest++ = c;
}
BackUpLimit = Dest-1; // backup pointer. points to last '\'
//
// update the src pointer past the prefix and slashes
//
Src += ExpectedPrefixLength-1;
while (ISSLASH(*Src)) {
Src++;
}
//
// error if nothing after expected prefix
//
if (*Src == '\0') {
RetCode = ERROR_FILE_NOT_FOUND;
}
}
else {
RetCode = ERROR_PATH_NOT_FOUND;
}
if (RetCode) {
goto ErrorExit;
}
/* target
|
V
at this point, the target contains \OS2SS\xxx\xxx\
source
|
the source points after the expected prefix V
\SEM32\\
*/
}
/*
copy user string
*Dest -> first char after d:\
*src -> first char after d:\
if we see a metacharacter, we verify that they're allowed. if there
is a metacharacter in any component other than the last, we return
an error.
*/
LastComponent = Dest; // LastComponent points to first letter
while (*Src) {
//
// if we get here and meta characters have already been found, they
// aren't in the last component, so we return an error.
//
if (OutputFlags & CANONICALIZE_META_CHARS_FOUND) {
RetCode = ERROR_PATH_NOT_FOUND;
goto ErrorExit;
}
RemoveBlanksAndDots=TRUE;
//
// if path is '.', copy . and don't remove dots
//
if ((*Src == '.') &&
(ISPATHSEP(Src[1]))) {
Src++;
Dest--;
RemoveBlanksAndDots=FALSE;
}
//
// else if path is '..', copy .. and don't remove dots
//
else if ((Src[0] == '.') &&
(Src[1] == '.') ) {
if (Src[2] == '.') {
RetCode = ERROR_PATH_NOT_FOUND;
goto ErrorExit;
}
if (ISPATHSEP(Src[2])) {
Src += 2; // Src points past ..
Dest -= 2; // Dest points to char before last path sep
#ifdef DBCS
// MSKK Feb.28.1993 V-AkihiS
{
PSZ String, LastSlashPtr;
String = LastSlashPtr = NameBuffer;
while (String <= Dest) {
if (Ow2NlsIsDBCSLeadByte(*String, SesGrp->DosCP)) {
String++;
if (String <= Dest) {
String++;
}
} else {
if (ISSLASH(*String)) {
if (String >= BackUpLimit) {
LastSlashPtr = String;
}
}
String++;
}
}
if (ISSLASH(*LastSlashPtr)) {
Dest = LastSlashPtr;
} else {
Dest = BackUpLimit - 1;
RetCode = ERROR_PATH_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
}
#else
while ((Dest >= BackUpLimit) && !(ISSLASH(*Dest))) { // have to use ISSLASH because of MapToRootName
Dest--; // BUGBUG make DBCS correct
}
if (!ISSLASH(*Dest)) {
RetCode = ERROR_PATH_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
#endif
RemoveBlanksAndDots=FALSE;
}
else {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit;
}
}
//
// else copy path
//
else {
while (!ISPATHSEP(*Src)) {
c = *Src++;
if ((c == '?') || (c == '*')) {
if (!MetaCharactersAllowed) {
RetCode = ERROR_PATH_NOT_FOUND;
goto ErrorExit;
}
else {
OutputFlags |= CANONICALIZE_META_CHARS_FOUND;
}
}
#ifdef DBCS
// MSKK Apr.18.1993 V-AkihiS
if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
*Dest++ = c;
if (*Src) {
//
// Check Trailing byte is valid or not.
//
if ((UCHAR)*Src < 0x40 || (UCHAR)*Src > 0xFC || (UCHAR)*Src == 0x7F) {
RetCode = ERROR_INVALID_NAME;
goto ErrorExit;
} else {
*Dest++ = *Src++;
}
} else {
RetCode = ERROR_INVALID_NAME;
goto ErrorExit;
}
}
else {
if (ValidateChars && ((UCHAR)c < (UCHAR)' ' ||
strchr( InvalidCharacters, c )
)
) {
RetCode = ERROR_INVALID_NAME;
goto ErrorExit;
}
if ((!PreserveCase) && (c >= 'a' && c <= 'z')) {
c = (CHAR) (c - 'a' + 'A');
}
*Dest++ = c;
}
#else
if (ValidateChars && ((UCHAR)c < (UCHAR)' ' ||
strchr( Od2InvalidCharacters, c )
)
) {
RetCode = ERROR_INVALID_NAME;
goto ErrorExit;
}
if ((!PreserveCase) && (c >= 'a' && c <= 'z')) {
c = (CHAR) (c - 'a' + 'A');
}
*Dest++ = c;
#endif
}
}
//
// truncate trailing dots and blanks here. if there is a metacharacter
// in the name, we must leave one trailing dot, if there is one.
// DBCS correct because '.' and ' ' aren't valid trailing bytes
//
if (RemoveBlanksAndDots) {
if ((Dest > LastComponent) && ((*(Dest-1) == '.') || (*(Dest-1) == ' '))) {
do {
Dest--;
} while ((Dest > LastComponent) && ((*(Dest-1) == '.') || (*(Dest-1) == ' ')));
if (OutputFlags & CANONICALIZE_META_CHARS_FOUND) {
if (*Dest == '.') {
Dest++;
}
}
}
if (Dest <= LastComponent) {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
}
// *Src == '\' or '/'
if (ISSLASH(*Src)) {
if (MapToRootName) {
*Dest++ = '/';
}
else {
*Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
}
LastComponent = Dest;
while (ISSLASH(*Src)) {
Src++; // eat up extra '\'s
}
}
}
//
// null terminate
//
*Dest = '\0';
if (OutputType != FILE_TYPE_FILE &&
OutputType != FILE_TYPE_DEV &&
OutputType != FILE_TYPE_PSDEV
) {
if (Dest == LastComponent || Dest <= BackUpLimit) {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
if (OutputType == FILE_TYPE_NMPIPE && !TestForPipe(Os2Name)) {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit;
}
else if (OutputType == FILE_TYPE_MAILSLOT && !TestForMailslot(Os2Name)) {
RetCode = ERROR_FILE_NOT_FOUND;
goto ErrorExit;
}
}
//
// Enforce 260 max path length. remember that length does not include
// the terminating null. Remember the 260 limit includes the null byte.
//
ASSERT (Os2Name != NULL);
if (strlen(Os2Name) > CCHMAXPATH - 1) {
RetCode = ERROR_FILENAME_EXCED_RANGE;
goto ErrorExit;
}
//
// do some file-specific stuff.
//
if (OutputType == FILE_TYPE_FILE) {
//
// detect root directory
// test for "d:". if so, map to "d:\"
//
if (NameBuffer[FIRST_SLASH+FILE_PREFIX_LENGTH] == '\0') { // resulting path is d:
NameBuffer[FIRST_SLASH+FILE_PREFIX_LENGTH] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
NameBuffer[ROOTDIRLENGTH+FILE_PREFIX_LENGTH] = '\0';
Dest++;
OutputFlags |= CANONICALIZE_IS_ROOT_DIRECTORY;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint("path is root dir\n");
}
#endif
}
else if (NameBuffer[FIRST_SLASH+FILE_PREFIX_LENGTH] == (CHAR)OBJ_NAME_PATH_SEPARATOR && NameBuffer[ROOTDIRLENGTH+FILE_PREFIX_LENGTH] == '\0') {
OutputFlags |= CANONICALIZE_IS_ROOT_DIRECTORY;
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint("path is root dir\n");
}
#endif
}
//
// test for "d:\pipe" or "d:\pipe\..." this is illegal unless
// CANONICALIZE_FILE_OR_DEV is specified. only DosMove sets this flag.
//
else if ((!(_strnicmp(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH,"PIPE",4))) &&
(((*(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH+PIPE_DIR_SIZE-2)) == 0) ||
((*(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH+PIPE_DIR_SIZE-2)) == (CHAR)OBJ_NAME_PATH_SEPARATOR))) {
if (ExpectedType != CANONICALIZE_FILE_OR_DEV) {
RetCode = ERROR_PATH_NOT_FOUND;
goto ErrorExit; // go free buffer(s) and return error
}
}
//
// optimize to use open handle to current directory if 1) the user doesn't
// need the full path (i.e. not for current directory operations) 2) we
// have the current directory (the user didn't specify a full path), and
// 3) current directory isn't root.
//
if ((ARGUMENT_PRESENT( DirectoryHandle )) &&
(CurrentDirectoryHandle != NULL) &&
(!_strnicmp(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH,
CurrentDirectoryString->Buffer,
CurrentDirectoryString->Length)) &&
(NameBuffer[DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH+
CurrentDirectoryString->Length] == '\\')
) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint("Optimized relative path\n");
}
#endif
*DirectoryHandle = CurrentDirectoryHandle;
//
// we have to return a pointer to the relative path. we can
// either allocate a second buffer and copy the name from
// the current directory on, or ripple copy the relative path
// over the full path. since the ripple copy is less work, we
// do it.
//
// if canonical path is "\os2ss\drives\a:\dir1\dir2" and current
// directory is "\os2ss\drives\a:\dir1", we want to copy "dir2"
// to the beginning of the buffer.
//
Src = NameBuffer+CurrentDirectoryString->Length+1+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH;
Dest = NameBuffer;
while (*Dest++ = *Src++)
;
Dest--;
}
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint("got to here. name is %s\n",NameBuffer);
if (DirectoryHandle != NULL)
DbgPrint(" handle is %ld\n",*DirectoryHandle);
}
#endif
CanonicalString->MaximumLength = (USHORT) NameBufferLength;
CanonicalString->Length = (USHORT) (Dest - NameBuffer);
CanonicalString->Buffer = NameBuffer;
#if 0
#ifndef DBCS // MSKK move max path length check
//
// Enforce 260 max path length. remember that length does not include
// the terminating null. Remember the 260 limit includes the null byte.
//
ASSERT (Os2Name != NULL);
if (CanonicalString->Length - (Os2Name - NameBuffer) >=
CCHMAXPATH) {
RetCode = ERROR_PATH_NOT_FOUND;
}
#endif
#endif // 0
ErrorExit:
if (CurrentDirectoryString != NULL) {
RtlFreeHeap( Od2Heap, 0, CurrentDirectoryString );
}
if (RetCode != NO_ERROR) {
if (NameBuffer != NULL) {
RtlFreeHeap( Od2Heap, 0, NameBuffer );
}
}
else {
if (ARGUMENT_PRESENT( ParseFlags )) {
*ParseFlags = OutputFlags;
}
if (ExpectedPrefix == NULL && ARGUMENT_PRESENT( FileType )) {
*FileType = OutputType;
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
DbgPrint( "Od2Canonicalize: returning path %s\n", NameBuffer);
}
#endif
}
return( RetCode );
}
BOOLEAN
Od2IsAbsolutePath(
IN PSZ Path
)
{
CHAR c;
if (Path[ 0 ] && Path[ 1 ] != ':') {
while (c = *Path++) {
if (c == '/' || c == (CHAR)OBJ_NAME_PATH_SEPARATOR) {
return( TRUE );
}
#ifdef DBCS
// MSKK Apr.11.1993 V-AkihiS
if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
if (*Path) Path++;
}
#endif
}
return( FALSE );
}
else {
return( TRUE );
}
}