[prev in list] [next in list] [prev in thread] [next in thread] 

List:       squeak-dev
Subject:    [squeak-dev] Re: Review Request: noUNCPaths
From:       Marcel Taeumel via Squeak-dev <squeak-dev () lists ! squeakfoundation ! org>
Date:       2023-08-31 12:52:10
Message-ID: Mailbird-4e8a2328-05dd-4e99-97b2-12042a34a167 () hpi ! de
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Merged:

- Win32 platform code changes
- Commentary in FilePlugin (VMMaker-Plugins)
- Commentary in FileDirectory (Files package in image)


Best,
Marcel
Am 31.08.2023 12:11:51 schrieb christoph.thiede@student.hpi.uni-potsdam.de \
<christoph.thiede@student.hpi.uni-potsdam.de>: Hi,

as MailComposition destroyed the git patch format, please find the correct patch file \
in the attachment.

Best,
Christoph

---
Sent from Squeak Inbox Talk

On 2023-08-17T13:40:35+02:00, christoph.thiede@student.hpi.uni-potsdam.de wrote:

> Hi Eliot,
> 
> with a pretty long delay, here's a revision of the patch that includes more \
> examples as requested. Could you merge that now? :-) 
> Best,
> Christoph
> 
> 
> Repairs FileDirectory>>#exists for long paths (> 260 characters) on Windows by \
> well-defining an edge case in the Windows implementation of the FilePlugin \
> primitiveDirectoryEntry, that is, to specify a single dot (.) as the file name. \
> Documents the present limitations to syntactic sugar in long file paths in the \
> platform code, the relevant plugin methods, and on the image side of Squeak Trunk. 
> An alternative consideration was to rewrite FileDirectory>>#exists to pass an empty \
> string as file name to the primitive instead of modifying the VM, but strictly \
> speaking, even this would have exploited an undefined behavior in the VM plugin, \
> and an empty file name would be less idiomatic than a single dot. 
> For the original bug report, see: \
> https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 Thanks to \
> Marcel (mt) for his support! 
> Revision (4): Added example paths to comments and fixed erratum in comment of \
> FilePlugin>>#primitiveDirectoryEntry. 
> Signed-off-by: Christoph Thiede
> ---
> Note that this mail contains both a git diff for the changes in the \
> opensmalltalk-vm repository and a changeset for the changes in the Squeak Trunk so \
> that they may be reviewed together. Any feedback on this formatting approach will \
> be appreciated. Excited to receive your review! 
> platforms/win32/vm/sqWin32Directory.c | 42 +++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
> 
> diff --git a/platforms/win32/vm/sqWin32Directory.c \
> b/platforms/win32/vm/sqWin32Directory.c index 2b3d090ec..42c4af02b 100644
> --- a/platforms/win32/vm/sqWin32Directory.c
> +++ b/platforms/win32/vm/sqWin32Directory.c
> @@ -196,6 +196,21 @@ sqInt dir_Lookup(char *pathString, sqInt pathLength, sqInt \
> index, /* Lookup the index-th entry of the directory with the given path, starting
> at the root of the file system. Set the name, name length, creation date,
> creation time, directory flag, and file size (if the entry is a file).
> +
> + Note that, due to restrictions by the operating system, this method only
> + has limited support for paths longer than 260 characters. In the case of
> + longer paths, they must not contain syntactic sugar such as ".", "..", or
> + "a/b"*:
> +
> + * DON'T: dir_Lookup("\foo\.", ...)
> + * DON'T: dir_Lookup("\foo\..", ...)
> + * DON'T: dir_Lookup("\foo/bar", ...)
> +
> + For more details, see:
> + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
> + *) Long paths are automatically converted into UNC paths, which only
> + support a subset of the normal path syntax.
> +
> Return:
> 0 if a entry is found at the given index
> 1 if the directory has fewer than index entries
> @@ -354,6 +369,27 @@ sqInt dir_EntryLookup(char *pathString, sqInt pathLength, \
> char* nameString, sqIn /* Lookup a given file in a given named directory.
> Set the name, name length, creation date,
> creation time, directory flag, and file size (if the entry is a file).
> +
> + Note that, due to restrictions by the operating system, this method only
> + has limited support for paths longer than 260 characters (for the full
> + path concatenated from the directory path, a backslash, and the file
> + name). In the case of longer paths, neither the path nor the file name
> + must contain syntactic sugar such as ".", "..", or "a/b"*. However, this
> + method defines a single (!) convention for passing the full nameString as
> + ".", which is also supported for long paths. This convention is provided
> + for an efficient existence check of the directory (e.g.,
> + FileDirectory>>#exists):
> +
> + * DON'T: dir_EntryLookup("", .., "foo\.", ...)
> + * DON'T: dir_EntryLookup("", .., "foo\..", ...)
> + * DON'T: dir_EntryLookup("", .., "foo/bar", ...)
> + * DO: dir_EntryLookup("", .., ".", ...)
> +
> + For more details, see:
> + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
> + *) Long paths are automatically converted into UNC paths, which only
> + support a subset of the normal path syntax.
> +
> Return:
> 0 if found (a file or directory 'nameString' exists in directory 'pathString')
> 1 if the directory has no such entry
> @@ -416,6 +452,12 @@ sqInt dir_EntryLookup(char *pathString, sqInt pathLength, \
> char* nameString, sqIn fullPath=(char *)calloc(fullPathLength,sizeof(char));
> memcpy(fullPath,pathString,pathLength);
> if (pathString[pathLength-1] != '\\') fullPath[pathLength]='\\';
> + if (nameStringLength == 1 && nameString[0] == '.') {
> + /* special syntax: "." is the current directory. Trim it from the full
> + path to avoid generating a UNC path with an unresolved ".", which is
> + not supported there. See comment above. */
> + nameStringLength = 0;
> + }
> memcpy(fullPath+fullPathLength-nameStringLength,nameString,nameStringLength);
> 
> /* convert the path name into a null-terminated C string */
> --
> 2.37.3.windows.1
> 
> =============== Summary ===============
> 
> Change Set: noUNCPaths
> Date: 30 November 2022
> Author: Christoph Thiede
> 
> Documents the present limitations to syntactic sugar in long file paths in the \
> relevant plugin methods and on the image side. 
> For the original bug report, see: \
> https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 Thanks to \
> Marcel (mt) for his support! 
> Revision (4): Added example paths to comments and fixed erratum in comment of \
> FilePlugin>>#primitiveDirectoryEntry. 
> =============== Diff ===============
> 
> FileDirectory>>primLookupEntryIn:index: {private}  · ct 8/17/2023 13:26 (changed)
> primLookupEntryIn: fullPath index: index
> "Look up the index-th entry of the directory with the given fully-qualified path \
> (i.e., starting from the root of the file hierarchy) and return an array \
> containing: 
> 
> 
> The empty string enumerates the top-level files or drives. (For example, on Unix, \
> the empty path enumerates the contents of '/'. On Macs and PCs, it enumerates the \
> mounted volumes/drives.) + Note that in general, fullPath must not contain \
> syntactic sugar for the current platform (e.g., '.' or '..', or on Windows, forward \
> slashes instead of backslashes). These conventions are only fully supported on Unix \
> platforms; on Windows, they are only supported for short non-UNC file paths \
> containing max 260 characters: + DON'T: self primLookupEntryIn: '\foo\.' index: ...
> + DON'T: self primLookupEntryIn: '\foo\..' index: ...
> + DON'T (on Windows): self primLookupEntryIn: '\foo/bar' index: ...
> + See the comment in the primitive implementation for more details.
> 
> The creation and modification times are in seconds since the start of the Smalltalk \
> time epoch. DirFlag is true if the entry is a directory. FileSize the file size in \
> bytes or zero for directories. The primitive returns nil when index is past the end \
> of the directory. It fails if the given path is bad." 
> 
> ^ #badDirectoryPath
> 
> 
> 
> FileDirectory>>primLookupEntryIn:name: {private}  · ct 8/17/2023 13:28 (changed)
> primLookupEntryIn: fullPath name: fName
> -
> "Look up (a simple file name) in the directory identified by
> and return an array containing:
> 
> 
> 
> On Unix, the empty path denotes '/'.
> On Macs and PCs, it is the container of the system volumes.)
> + Note that in general, neither fullPath nor fName must contain syntactic sugar for \
> the current platform (e.g., '.' or '..', or on Windows, forward slashes instead of \
> backslashes). These conventions are only fully supported on Unix platforms; on \
> Windows, they are only supported for short non-UNC file paths containing max 260 \
> characters (for the full path concatenated from the directory path, a backslash, \
> and the file name). As a single (!) exception, the file name may always be a single \
> dot ('.'), which is supported for an efficient existence test of the directory path \
> (e.g., FileDirectory>>#exists): + DON'T: self primLookupEntryIn: '' name: \
> 'plonk\.'. + DON'T: self primLookupEntryIn: '' name: 'plonk\..'.
> + DON'T (on Windows): self primLookupEntryIn: '' name: 'foo/bar'.
> + DO: self primLookupEntryIn: '' name: '.'.
> + See the comment in the primitive implementation for more details.
> 
> The creation and modification times are in seconds since the start of the Smalltalk \
> time epoch. DirFlag is true if the entry is a directory. FileSize the file size in \
> bytes or zero for directories. The primitive returns nil when index is past the end \
> of the directory. It fails if the given path is bad." 
> 
> 
> ^ #primFailed "to distinguish from nil"
> 
> 
> 
> FilePlugin>>primitiveDirectoryEntry {directory primitives}  · ct 8/17/2023 13:28 \
> (changed) primitiveDirectoryEntry
> 
> "Two arguments - directory path, and simple file name;
> returns an array (see primitiveDirectoryLookup) describing the file or directory,
> or nil if it does not exist.
> +
> + Note that in general, the directory path name must not contain syntactic
> + sugar for the current platform (e.g., '.' or '..', or on Windows, forward slashes
> + instead of backslashes). These conventions are only fully supported on Unix
> + platforms; on Windows, they are only supported for short non-UNC file paths
> + containing max 260 characters (for the full path concatenated from the
> + directory path, a backslash, and the file name):
> + DON'T: primitiveDirectoryEntry '\foo\.' ...
> + DON'T: primitiveDirectoryEntry '\foo\..' ...
> + DON'T (on Windows): primitiveDirectoryEntry '\foo/bar' ...
> + See the comment in sqWin32Directory.c for more details.
> +
> Primitive fails if the outer path does not identify a readable directory.
> (This is a lookup-by-name variant of primitiveDirectoryLookup.)"
> 
> > requestedName pathName pathNameIndex pathNameSize status entryName entryNameSize \
> > createDate modifiedDate dirFlag posixPermissions symlinkFlag fileSize okToList \
> > reqNameIndex reqNameSize |
> 
> 
> 
> 
> 
> 
> 
> requestedName := interpreterProxy stackValue: 0.
> pathName := interpreterProxy stackValue: 1.
> (interpreterProxy isBytes: pathName) ifFalse:
> [^interpreterProxy primitiveFail].
> 
> "Outbound string parameters"
> pathNameIndex := interpreterProxy firstIndexableField: pathName.
> pathNameSize := interpreterProxy byteSizeOf: pathName.
> 
> reqNameIndex := interpreterProxy firstIndexableField: requestedName.
> reqNameSize := interpreterProxy byteSizeOf: requestedName.
> self cCode: '' inSmalltalk:
> [entryName := ByteString new: 256.
> entryNameSize := createDate := modifiedDate := dirFlag := fileSize := \
> posixPermissions := symlinkFlag := nil]. "If the security plugin can be loaded, use \
> it to check for permission. If not, assume it's ok"
> okToList := sCLPfn ~= 0
> ifTrue: [self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, \
>                 pathNameSize)' inSmalltalk: [true]]
> ifFalse: [true].
> status := okToList
> ifTrue:
> [self dir_EntryLookup: pathNameIndex _: pathNameSize
> _: reqNameIndex _: reqNameSize
> _: entryName _: (self addressOf: entryNameSize put: [:v| entryNameSize := v])
> _: (self addressOf: createDate put: [:v| createDate := v])
> _: (self addressOf: modifiedDate put: [:v| modifiedDate := v])
> _: (self addressOf: dirFlag put: [:v| dirFlag := v])
> _: (self addressOf: fileSize put: [:v| fileSize := v])
> _: (self addressOf: posixPermissions put: [:v| posixPermissions := v])
> _: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])]
> ifFalse:
> [DirNoMoreEntries].
> 
> interpreterProxy failed ifTrue:
> [^nil].
> status = DirNoMoreEntries ifTrue: "no entry; return nil"
> [interpreterProxy "pop pathName, index, rcvr"
> pop: 3 thenPush: interpreterProxy nilObject.
> ^nil].
> status = DirBadPath ifTrue:
> [^interpreterProxy primitiveFail]."bad path"
> 
> interpreterProxy
> pop: 3 "pop pathName, index, rcvr"
> thenPush:
> (self
> cppIf: PharoVM
> ifTrue:
> [self
> makeDirEntryName: entryName
> size: entryNameSize
> createDate: createDate
> modDate: modifiedDate
> isDir: dirFlag
> fileSize: fileSize
> posixPermissions: posixPermissions
> isSymlink: symlinkFlag]
> ifFalse:
> [self
> makeDirEntryName: entryName
> size: entryNameSize
> createDate: createDate
> modDate: modifiedDate
> isDir: dirFlag
> fileSize: fileSize])
> 
> FilePlugin>>primitiveDirectoryLookup {directory primitives}  · ct 8/17/2023 13:30 \
> (changed) primitiveDirectoryLookup
> + "Two arguments - directory path, and an index to an item; returns an array (see \
> primitiveDirectoryLookup) describing the file or directory, or nil if it does not \
> exist. +
> + Note that in general, the directory path must not contain syntactic sugar for the \
> current platform (e.g., '.' or '..', or on Windows, forward slashes instead of \
> backslashes). These conventions are only fully supported on Unix platforms; on \
> Windows, they are only supported for short non-UNC file paths containing max 260 \
> characters: + DON'T: primitiveDirectoryLookup '' 'foo\.'
> + DON'T: primitiveDirectoryLookup '' foo\..'
> + DON'T (on Windows): primitiveDirectoryLookup '' 'foo/bar'
> + DO: primitiveDirectoryLookup '' '.'
> + See the comment in sqWin32Directory.c for more details.
> +
> + Primitive fails if the outer path does not identify a readable directory. (For a \
> lookup-by-name variant, see primitiveDirectoryEntry.)" 
> > index pathName pathNameIndex pathNameSize status entryName entryNameSize \
> > createDate modifiedDate dirFlag symlinkFlag posixPermissions fileSize okToList |
> 
> 
> 
> 
> 
> 
> index := interpreterProxy stackIntegerValue: 0.
> pathName := interpreterProxy stackValue: 1.
> (interpreterProxy isBytes: pathName)
> ifFalse: [^interpreterProxy primitiveFail].
> pathNameIndex := interpreterProxy firstIndexableField: pathName.
> pathNameSize := interpreterProxy byteSizeOf: pathName.
> self cCode: '' inSmalltalk:
> [entryName := ByteString new: 256.
> entryNameSize := createDate := modifiedDate := dirFlag := fileSize := \
> posixPermissions := symlinkFlag := nil]. "If the security plugin can be loaded, use \
> it to check for permission. If not, assume it's ok"
> okToList := sCLPfn ~= 0
> ifTrue: [self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, \
>                 pathNameSize)' inSmalltalk: [true]]
> ifFalse: [true].
> status := okToList
> ifTrue:
> [self dir_Lookup: pathNameIndex _: pathNameSize
> _: index
> _: entryName _: (self addressOf: entryNameSize put: [:v| entryNameSize := v])
> _: (self addressOf: createDate put: [:v| createDate := v])
> _: (self addressOf: modifiedDate put: [:v| modifiedDate := v])
> _: (self addressOf: dirFlag put: [:v| dirFlag := v])
> _: (self addressOf: fileSize put: [:v| fileSize := v])
> _: (self addressOf: posixPermissions put: [:v| posixPermissions := v])
> _: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])]
> ifFalse: [DirNoMoreEntries].
> interpreterProxy failed ifTrue:
> [^nil].
> status = DirNoMoreEntries ifTrue: "no more entries; return nil"
> [interpreterProxy "pop pathName, index, rcvr"
> pop: 3 thenPush: interpreterProxy nilObject.
> ^nil].
> status = DirBadPath ifTrue:
> [^interpreterProxy primitiveFail]."bad path"
> 
> interpreterProxy
> pop: 3 "pop pathName, index, rcvr"
> thenPush:
> (self
> cppIf: PharoVM
> ifTrue:
> [self
> makeDirEntryName: entryName
> size: entryNameSize
> createDate: createDate
> modDate: modifiedDate
> isDir: dirFlag
> fileSize: fileSize
> posixPermissions: posixPermissions
> isSymlink: symlinkFlag]
> ifFalse:
> [self
> makeDirEntryName: entryName
> size: entryNameSize
> createDate: createDate
> modDate: modifiedDate
> isDir: dirFlag
> fileSize: fileSize])
> 
> ---
> Sent from Squeak Inbox Talk
> ["noUNCPaths.4.cs"]
> 
> On 2022-11-30T07:16:49-08:00, eliot.miranda(a)gmail.com wrote:
> 
> > Oops! I see you did cc. I should stop reading email in my phone. The letterbox is \
> > too small. 
> > _,,,^..^,,,_ (phone)
> > 
> > > On Nov 30, 2022, at 7:16 AM, Eliot Miranda wrote:
> > > 
> > > Hi Christoph,
> > > 
> > > looks good. Please cc messages like this which are relevant to the vm to vm-dev \
> > > (aka opensmalltalk-vm). I would love to see some example paths in the comments \
> > > below rather than just "don't include ‘..' ‘.'). Show a path that would be \
> > > converted to unc path vs a proper windows path. People coming to the vm may not \
> > > have experience with all platforms. Over commenting is a much better evil than \
> > > overcommenting :-) 
> > > Sorry for top posting
> > > _,,,^..^,,,_ (phone)
> > > 
> > > > > On Nov 30, 2022, at 6:58 AM, Christoph.Thiede at student.hpi.uni-potsdam.de \
> > > > > wrote: 
> > > > Repairs FileDirectory>>#exists for long paths (> 260 characters) on Windows \
> > > > by well-defining an edge case in the Windows implementation of the FilePlugin \
> > > > primitiveDirectoryEntry, that is, to specify a single dot (.) as the file \
> > > > name. Documents the present limitations to syntactic sugar in long file paths \
> > > > in the platform code, the relevant plugin methods, and on the image side of \
> > > > Squeak Trunk. 
> > > > An alternative consideration was to rewrite FileDirectory>>#exists to pass an \
> > > > empty string as file name to the primitive instead of modifying the VM, but \
> > > > strictly speaking, even this would have exploited an undefined behavior in \
> > > > the VM plugin, and an empty file name would be less idiomatic than a single \
> > > > dot. 
> > > > For the original bug report, see: \
> > > > https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 \
> > > > Thanks to Marcel (mt) for his support! 
> > > > Signed-off-by: Christoph Thiede
> > > > ---
> > > > Note that this mail contains both a git diff for the changes in the \
> > > > opensmalltalk-vm repository and a changeset for the changes in the Squeak \
> > > > Trunk so that they may be reviewed together. Any feedback on this formatting \
> > > > approach will be appreciated. Excited to receive your review! 
> > > > platforms/win32/vm/sqWin32Directory.c | 29 +++++++++++++++++++++++++++
> > > > 1 file changed, 29 insertions(+)
> > > > 
> > > > diff --git a/platforms/win32/vm/sqWin32Directory.c \
> > > > b/platforms/win32/vm/sqWin32Directory.c index 2b3d090ec..0aa5c2108 100644
> > > > --- a/platforms/win32/vm/sqWin32Directory.c
> > > > +++ b/platforms/win32/vm/sqWin32Directory.c
> > > > @@ -196,6 +196,15 @@ sqInt dir_Lookup(char *pathString, sqInt pathLength, \
> > > > sqInt index, /* Lookup the index-th entry of the directory with the given \
> > > > path, starting at the root of the file system. Set the name, name length, \
> > > > creation date, creation time, directory flag, and file size (if the entry is \
> > > > a file). +
> > > > + Note that, due to restrictions by the operating system, this method only
> > > > + has limited support for paths longer than 260 characters. In the case of
> > > > + longer paths, they must not contain syntactic sugar such as ".", "..", or
> > > > + "a/b".* For more details, see:
> > > > + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
> > > > + *) Long paths are automatically converted into UNC paths, which only
> > > > + support a subset of the normal path syntax.
> > > > +
> > > > Return:
> > > > 0 if a entry is found at the given index
> > > > 1 if the directory has fewer than index entries
> > > > @@ -354,6 +363,20 @@ sqInt dir_EntryLookup(char *pathString, sqInt \
> > > > pathLength, char* nameString, sqIn /* Lookup a given file in a given named \
> > > > directory. Set the name, name length, creation date,
> > > > creation time, directory flag, and file size (if the entry is a file).
> > > > +
> > > > + Note that, due to restrictions by the operating system, this method only
> > > > + has limited support for paths longer than 260 characters (for the full
> > > > + path concatenated from the directory path, a backslash, and the file
> > > > + name). In the case of longer paths, neither the path nor the file name
> > > > + must contain syntactic sugar such as ".", "..", or "a/b".* However, this
> > > > + method defines a single (!) convention for passing nameString as ".",
> > > > + which is also supported for long paths. This convention is provided for
> > > > + an efficient existence check of the directory (e.g.,
> > > > + FileDirectory>>#exists). For more details, see:
> > > > + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
> > > > + *) Long paths are automatically converted into UNC paths, which only
> > > > + support a subset of the normal path syntax.
> > > > +
> > > > Return:
> > > > 0 if found (a file or directory 'nameString' exists in directory \
> > > > 'pathString') 1 if the directory has no such entry
> > > > @@ -416,6 +439,12 @@ sqInt dir_EntryLookup(char *pathString, sqInt \
> > > > pathLength, char* nameString, sqIn fullPath=(char \
> > > > *)calloc(fullPathLength,sizeof(char)); \
> > > > memcpy(fullPath,pathString,pathLength); if (pathString[pathLength-1] != '\\') \
> > > > fullPath[pathLength]='\\'; + if (nameStringLength == 1 && nameString[0] == \
> > > > '.') { + /* special syntax: "." is the current directory. Trim it from the \
> > > > full + path to avoid generating a UNC path with an unresolved ".", which is
> > > > + not supported there. See comment above. */
> > > > + nameStringLength = 0;
> > > > + }
> > > > memcpy(fullPath+fullPathLength-nameStringLength,nameString,nameStringLength);
> > > > 
> > > > /* convert the path name into a null-terminated C string */
> > > > --
> > > > 2.37.3.windows.1
> > > > 
> > > > =============== Summary ===============
> > > > 
> > > > Change Set: noUNCPaths
> > > > Date: 30 November 2022
> > > > Author: Christoph Thiede
> > > > 
> > > > Documents the present limitations to syntactic sugar in long file paths in \
> > > > the relevant plugin methods and on the image side. 
> > > > For the original bug report, see: \
> > > > https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 \
> > > > Thanks to Marcel (mt) for his support! 
> > > > =============== Diff ===============
> > > > 
> > > > FileDirectory>>primLookupEntryIn:index: {private}  · ct 11/29/2022 20:24 \
> > > >                 (changed)
> > > > primLookupEntryIn: fullPath index: index
> > > > "Look up the index-th entry of the directory with the given fully-qualified \
> > > > path (i.e., starting from the root of the file hierarchy) and return an array \
> > > > containing: 
> > > > 
> > > > 
> > > > The empty string enumerates the top-level files or drives. (For example, on \
> > > > Unix, the empty path enumerates the contents of '/'. On Macs and PCs, it \
> > > > enumerates the mounted volumes/drives.) + Note that in general, fullPath must \
> > > > not contain syntactic sugar for the current platform (e.g., '.' or '..', or \
> > > > on Windows, forward slashes instead of backslashes). These conventions are \
> > > > only fully supported on Unix platforms; on Windows, they are only supported \
> > > > for short non-UNC file paths containing max 260 characters. See the comment \
> > > > in the primitive implementation for more details. 
> > > > The creation and modification times are in seconds since the start of the \
> > > > Smalltalk time epoch. DirFlag is true if the entry is a directory. FileSize \
> > > > the file size in bytes or zero for directories. The primitive returns nil \
> > > > when index is past the end of the directory. It fails if the given path is \
> > > > bad." 
> > > > 
> > > > ^ #badDirectoryPath
> > > > 
> > > > 
> > > > 
> > > > FileDirectory>>primLookupEntryIn:name: {private}  · ct 11/30/2022 15:38 \
> > > >                 (changed)
> > > > primLookupEntryIn: fullPath name: fName
> > > > -
> > > > "Look up (a simple file name) in the directory identified by
> > > > and return an array containing:
> > > > 
> > > > 
> > > > 
> > > > On Unix, the empty path denotes '/'.
> > > > On Macs and PCs, it is the container of the system volumes.)
> > > > + Note that in general, neither fullPath nor fName must contain syntactic \
> > > > sugar for the current platform (e.g., '.' or '..', or on Windows, forward \
> > > > slashes instead of backslashes). These conventions are only fully supported \
> > > > on Unix platforms; on Windows, they are only supported for short non-UNC file \
> > > > paths containing max 260 characters (for the full path concatenated from the \
> > > > directory path, a backslash, and the file name). As a single (!) exception, \
> > > > the file name may always be a single dot ('.'), which is supported for an \
> > > > efficient existence test of the directory path (e.g., \
> > > > FileDirectory>>#exists). See the comment in the primitive implementation for \
> > > > more details. 
> > > > The creation and modification times are in seconds since the start of the \
> > > > Smalltalk time epoch. DirFlag is true if the entry is a directory. FileSize \
> > > > the file size in bytes or zero for directories. The primitive returns nil \
> > > > when index is past the end of the directory. It fails if the given path is \
> > > > bad." 
> > > > 
> > > > 
> > > > ^ #primFailed "to distinguish from nil"
> > > > 
> > > > 
> > > > 
> > > > FilePlugin>>primitiveDirectoryEntry {directory primitives}  · ct 11/30/2022 \
> > > > 15:13 (changed) primitiveDirectoryEntry
> > > > 
> > > > "Two arguments - directory path, and simple file name;
> > > > returns an array (see primitiveDirectoryLookup) describing the file or \
> > > > directory, or nil if it does not exist.
> > > > +
> > > > + Note that in general, neither the directory path nor the file name must
> > > > + contain syntactic sugar for the current platform (e.g., '.' or '..', or on
> > > > + Windows, forward slashes instead of backslashes). These conventions are
> > > > + only fully supported on Unix platforms; on Windows, they are only
> > > > + supported for short non-UNC file paths containing max 260 characters (for
> > > > + the full path concatenated from the directory path, a backslash, and the
> > > > + file name). As a single (!) exception, the file name may always be a
> > > > + single dot ('.'), which is supported for an efficient existence test of
> > > > + the directory path (e.g., FileDirectory>>#exists). See the comment in
> > > > + sqWin32Directory.c for more details.
> > > > +
> > > > Primitive fails if the outer path does not identify a readable directory.
> > > > (This is a lookup-by-name variant of primitiveDirectoryLookup.)"
> > > > 
> > > > > requestedName pathName pathNameIndex pathNameSize status entryName \
> > > > > entryNameSize createDate modifiedDate dirFlag posixPermissions symlinkFlag \
> > > > > fileSize okToList reqNameIndex reqNameSize |
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > requestedName := interpreterProxy stackValue: 0.
> > > > pathName := interpreterProxy stackValue: 1.
> > > > (interpreterProxy isBytes: pathName) ifFalse:
> > > > [^interpreterProxy primitiveFail].
> > > > 
> > > > "Outbound string parameters"
> > > > pathNameIndex := interpreterProxy firstIndexableField: pathName.
> > > > pathNameSize := interpreterProxy byteSizeOf: pathName.
> > > > 
> > > > reqNameIndex := interpreterProxy firstIndexableField: requestedName.
> > > > reqNameSize := interpreterProxy byteSizeOf: requestedName.
> > > > self cCode: '' inSmalltalk:
> > > > [entryName := ByteString new: 256.
> > > > entryNameSize := createDate := modifiedDate := dirFlag := fileSize := \
> > > > posixPermissions := symlinkFlag := nil]. "If the security plugin can be \
> > > > loaded, use it to check for permission. If not, assume it's ok"
> > > > okToList := sCLPfn ~= 0
> > > > ifTrue: [self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, \
> > > >                 pathNameSize)' inSmalltalk: [true]]
> > > > ifFalse: [true].
> > > > status := okToList
> > > > ifTrue:
> > > > [self dir_EntryLookup: pathNameIndex _: pathNameSize
> > > > _: reqNameIndex _: reqNameSize
> > > > _: entryName _: (self addressOf: entryNameSize put: [:v| entryNameSize := v])
> > > > _: (self addressOf: createDate put: [:v| createDate := v])
> > > > _: (self addressOf: modifiedDate put: [:v| modifiedDate := v])
> > > > _: (self addressOf: dirFlag put: [:v| dirFlag := v])
> > > > _: (self addressOf: fileSize put: [:v| fileSize := v])
> > > > _: (self addressOf: posixPermissions put: [:v| posixPermissions := v])
> > > > _: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])]
> > > > ifFalse:
> > > > [DirNoMoreEntries].
> > > > 
> > > > interpreterProxy failed ifTrue:
> > > > [^nil].
> > > > status = DirNoMoreEntries ifTrue: "no entry; return nil"
> > > > [interpreterProxy "pop pathName, index, rcvr"
> > > > pop: 3 thenPush: interpreterProxy nilObject.
> > > > ^nil].
> > > > status = DirBadPath ifTrue:
> > > > [^interpreterProxy primitiveFail]."bad path"
> > > > 
> > > > interpreterProxy
> > > > pop: 3 "pop pathName, index, rcvr"
> > > > thenPush:
> > > > (self
> > > > cppIf: PharoVM
> > > > ifTrue:
> > > > [self
> > > > makeDirEntryName: entryName
> > > > size: entryNameSize
> > > > createDate: createDate
> > > > modDate: modifiedDate
> > > > isDir: dirFlag
> > > > fileSize: fileSize
> > > > posixPermissions: posixPermissions
> > > > isSymlink: symlinkFlag]
> > > > ifFalse:
> > > > [self
> > > > makeDirEntryName: entryName
> > > > size: entryNameSize
> > > > createDate: createDate
> > > > modDate: modifiedDate
> > > > isDir: dirFlag
> > > > fileSize: fileSize])
> > > > 
> > > > FilePlugin>>primitiveDirectoryLookup {directory primitives}  · ct 11/30/2022 \
> > > > 15:00 (changed) primitiveDirectoryLookup
> > > > + "Two arguments - directory path, and an index to an item; returns an array \
> > > > (see primitiveDirectoryLookup) describing the file or directory, or nil if it \
> > > > does not exist. +
> > > > + Note that in general, the directory path must not contain syntactic sugar \
> > > > for the current platform (e.g., '.' or '..', or on Windows, forward slashes \
> > > > instead of backslashes). These conventions are only fully supported on Unix \
> > > > platforms; on Windows, they are only supported for short non-UNC file paths \
> > > > containing max 260 characters. See the comment in sqWin32Directory.c for more \
> > > > details. +
> > > > + Primitive fails if the outer path does not identify a readable directory. \
> > > > (For a lookup-by-name variant, see primitiveDirectoryEntry.)" 
> > > > > index pathName pathNameIndex pathNameSize status entryName entryNameSize \
> > > > > createDate modifiedDate dirFlag symlinkFlag posixPermissions fileSize \
> > > > > okToList |
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > index := interpreterProxy stackIntegerValue: 0.
> > > > pathName := interpreterProxy stackValue: 1.
> > > > (interpreterProxy isBytes: pathName)
> > > > ifFalse: [^interpreterProxy primitiveFail].
> > > > pathNameIndex := interpreterProxy firstIndexableField: pathName.
> > > > pathNameSize := interpreterProxy byteSizeOf: pathName.
> > > > self cCode: '' inSmalltalk:
> > > > [entryName := ByteString new: 256.
> > > > entryNameSize := createDate := modifiedDate := dirFlag := fileSize := \
> > > > posixPermissions := symlinkFlag := nil]. "If the security plugin can be \
> > > > loaded, use it to check for permission. If not, assume it's ok"
> > > > okToList := sCLPfn ~= 0
> > > > ifTrue: [self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, \
> > > >                 pathNameSize)' inSmalltalk: [true]]
> > > > ifFalse: [true].
> > > > status := okToList
> > > > ifTrue:
> > > > [self dir_Lookup: pathNameIndex _: pathNameSize
> > > > _: index
> > > > _: entryName _: (self addressOf: entryNameSize put: [:v| entryNameSize := v])
> > > > _: (self addressOf: createDate put: [:v| createDate := v])
> > > > _: (self addressOf: modifiedDate put: [:v| modifiedDate := v])
> > > > _: (self addressOf: dirFlag put: [:v| dirFlag := v])
> > > > _: (self addressOf: fileSize put: [:v| fileSize := v])
> > > > _: (self addressOf: posixPermissions put: [:v| posixPermissions := v])
> > > > _: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])]
> > > > ifFalse: [DirNoMoreEntries].
> > > > interpreterProxy failed ifTrue:
> > > > [^nil].
> > > > status = DirNoMoreEntries ifTrue: "no more entries; return nil"
> > > > [interpreterProxy "pop pathName, index, rcvr"
> > > > pop: 3 thenPush: interpreterProxy nilObject.
> > > > ^nil].
> > > > status = DirBadPath ifTrue:
> > > > [^interpreterProxy primitiveFail]."bad path"
> > > > 
> > > > interpreterProxy
> > > > pop: 3 "pop pathName, index, rcvr"
> > > > thenPush:
> > > > (self
> > > > cppIf: PharoVM
> > > > ifTrue:
> > > > [self
> > > > makeDirEntryName: entryName
> > > > size: entryNameSize
> > > > createDate: createDate
> > > > modDate: modifiedDate
> > > > isDir: dirFlag
> > > > fileSize: fileSize
> > > > posixPermissions: posixPermissions
> > > > isSymlink: symlinkFlag]
> > > > ifFalse:
> > > > [self
> > > > makeDirEntryName: entryName
> > > > size: entryNameSize
> > > > createDate: createDate
> > > > modDate: modifiedDate
> > > > isDir: dirFlag
> > > > fileSize: fileSize])
> > > > 
> > > > ---
> > > > Sent from Squeak Inbox Talk
> > > > ["noUNCPaths.3.cs"]
> > > 
> > > > 


[Attachment #5 (text/html)]

<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: \
Arial;color: #000000;text-align: left" dir="ltr">  Merged:<div><br></div><div>- Win32 \
platform code changes</div><div>- Commentary in FilePlugin \
(VMMaker-Plugins)</div><div>- Commentary in FileDirectory (Files package in \
image)<br><div><br></div><div>Best,</div><div>Marcel</div></div><div \
class="mb_sig"></div><blockquote class='history_container' type='cite' \
style='border-left-style:solid;border-width:1px; margin-top:20px; \
margin-left:0px;padding-left:10px;'>  <p style='color: #AAAAAA; margin-top: 10px;'>Am \
31.08.2023 12:11:51 schrieb christoph.thiede@student.hpi.uni-potsdam.de \
&lt;christoph.thiede@student.hpi.uni-potsdam.de&gt;:</p><div \
style='font-family:Arial,Helvetica,sans-serif'>Hi, <br>
<br>as MailComposition destroyed the git patch format, please find the correct patch \
file in the attachment. <br>
<br>Best,
<br>Christoph
<br>
<br>---
<br>Sent from Squeak Inbox Talk
<br>
<br>On 2023-08-17T13:40:35+02:00, christoph.thiede@student.hpi.uni-potsdam.de wrote:
<br>
<br>> Hi Eliot,
<br>> 
<br>> with a pretty long delay, here's a revision of the patch that includes more \
examples as requested. Could you merge that now? :-) <br>> 
<br>> Best,
<br>> Christoph
<br>> 
<br>> 
<br>> Repairs FileDirectory>>#exists for long paths (> 260 characters) on Windows by \
well-defining an edge case in the Windows implementation of the FilePlugin \
primitiveDirectoryEntry, that is, to specify a single dot (.) as the file name. \
Documents the present limitations to syntactic sugar in long file paths in the \
platform code, the relevant plugin methods, and on the image side of Squeak Trunk. \
<br>>  <br>> An alternative consideration was to rewrite FileDirectory>>#exists to \
pass an empty string as file name to the primitive instead of modifying the VM, but \
strictly speaking, even this would have exploited an undefined behavior in the VM \
plugin, and an empty file name would be less idiomatic than a single dot. <br>> 
<br>> For the original bug report, see: \
https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 Thanks to \
Marcel (mt) for his support! <br>> 
<br>> Revision (4): Added example paths to comments and fixed erratum in comment of \
FilePlugin>>#primitiveDirectoryEntry. <br>> 
<br>> Signed-off-by: Christoph Thiede 
<br>> ---
<br>> Note that this mail contains both a git diff for the changes in the \
opensmalltalk-vm repository and a changeset for the changes in the Squeak Trunk so \
that they may be reviewed together. Any feedback on this formatting approach will be \
appreciated. Excited to receive your review! <br>> 
<br>> platforms/win32/vm/sqWin32Directory.c | 42 +++++++++++++++++++++++++++
<br>> 1 file changed, 42 insertions(+)
<br>> 
<br>> diff --git a/platforms/win32/vm/sqWin32Directory.c \
b/platforms/win32/vm/sqWin32Directory.c <br>> index 2b3d090ec..42c4af02b 100644
<br>> --- a/platforms/win32/vm/sqWin32Directory.c
<br>> +++ b/platforms/win32/vm/sqWin32Directory.c
<br>> @@ -196,6 +196,21 @@ sqInt dir_Lookup(char *pathString, sqInt pathLength, sqInt \
index, <br>> /* Lookup the index-th entry of the directory with the given path, \
starting <br>> at the root of the file system. Set the name, name length, creation \
date, <br>> creation time, directory flag, and file size (if the entry is a file).
<br>> +
<br>> + Note that, due to restrictions by the operating system, this method only
<br>> + has limited support for paths longer than 260 characters. In the case of
<br>> + longer paths, they must not contain syntactic sugar such as ".", "..", or
<br>> + "a/b"*:
<br>> + 
<br>> + * DON'T: dir_Lookup("<very long="" path="">\foo\.", ...)
<br>> + * DON'T: dir_Lookup("<very long="" path="">\foo\..", ...)
<br>> + * DON'T: dir_Lookup("<very long="" path="">\foo/bar", ...)
<br>> + 
<br>> + For more details, see:
<br>> + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
<br>> + *) Long paths are automatically converted into UNC paths, which only
<br>> + support a subset of the normal path syntax.
<br>> +
<br>> Return:
<br>>                 0         if a entry is found at the given index
<br>>                 1        if the directory has fewer than index entries
<br>> @@ -354,6 +369,27 @@ sqInt dir_EntryLookup(char *pathString, sqInt pathLength, \
char* nameString, sqIn <br>> /* Lookup a given file in a given named directory.
<br>> Set the name, name length, creation date,
<br>> creation time, directory flag, and file size (if the entry is a file).
<br>> +
<br>> + Note that, due to restrictions by the operating system, this method only
<br>> + has limited support for paths longer than 260 characters (for the full
<br>> + path concatenated from the directory path, a backslash, and the file
<br>> + name). In the case of longer paths, neither the path nor the file name
<br>> + must contain syntactic sugar such as ".", "..", or "a/b"*. However, this
<br>> + method defines a single (!) convention for passing the full nameString as
<br>> + ".", which is also supported for long paths. This convention is provided
<br>> + for an efficient existence check of the directory (e.g.,
<br>> + FileDirectory>>#exists):
<br>> + 
<br>> + * DON'T: dir_EntryLookup("<very long="" path="">", .., "foo\.", ...)
<br>> + * DON'T: dir_EntryLookup("<very long="" path="">", .., "foo\..", ...)
<br>> + * DON'T: dir_EntryLookup("<very long="" path="">", .., "foo/bar", ...)
<br>> + * DO: dir_EntryLookup("<very long="" path="">", .., ".", ...)
<br>> + 
<br>> + For more details, see:
<br>> + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
<br>> + *) Long paths are automatically converted into UNC paths, which only
<br>> + support a subset of the normal path syntax.
<br>> +
<br>> Return:
<br>>                 0         if found (a file or directory 'nameString' exists in \
directory 'pathString') <br>>                 1        if the directory has no such \
entry <br>> @@ -416,6 +452,12 @@ sqInt dir_EntryLookup(char *pathString, sqInt \
pathLength, char* nameString, sqIn <br>> fullPath=(char \
*)calloc(fullPathLength,sizeof(char)); <br>> memcpy(fullPath,pathString,pathLength);
<br>> if (pathString[pathLength-1] != '\\') fullPath[pathLength]='\\';
<br>> + if (nameStringLength == 1 && nameString[0] == '.') {
<br>> + /* special syntax: "." is the current directory. Trim it from the full
<br>> + path to avoid generating a UNC path with an unresolved ".", which is
<br>> + not supported there. See comment above. */
<br>> + nameStringLength = 0;
<br>> + }
<br>> memcpy(fullPath+fullPathLength-nameStringLength,nameString,nameStringLength);
<br>> 
<br>> /* convert the path name into a null-terminated C string */
<br>> -- 
<br>> 2.37.3.windows.1
<br>> 
<br>> =============== Summary ===============
<br>> 
<br>> Change Set:                noUNCPaths
<br>> Date:                        30 November 2022
<br>> Author:                        Christoph Thiede
<br>> 
<br>> Documents the present limitations to syntactic sugar in long file paths in the \
relevant plugin methods and on the image side. <br>> 
<br>> For the original bug report, see: \
https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 Thanks to \
Marcel (mt) for his support! <br>> 
<br>> Revision (4): Added example paths to comments and fixed erratum in comment of \
FilePlugin>>#primitiveDirectoryEntry. <br>> 
<br>> =============== Diff ===============
<br>> 
<br>> FileDirectory>>primLookupEntryIn:index: {private}  · ct 8/17/2023 13:26 \
(changed) <br>> primLookupEntryIn: fullPath index: index
<br>>         "Look up the index-th entry of the directory with the given \
fully-qualified path (i.e., starting from the root of the file hierarchy) and return \
an array containing: <br>> 
<br>>         <name> <creationtime> <modificationtime> <dirflag> <filesize>
<br>> 
<br>>         The empty string enumerates the top-level files or drives. (For \
example, on Unix, the empty path enumerates the contents of '/'. On Macs and PCs, it \
enumerates the mounted volumes/drives.) <br>> +         Note that in general, \
fullPath must not contain syntactic sugar for the current platform (e.g., '.' or \
'..', or on Windows, forward slashes instead of backslashes). These conventions are \
only fully supported on Unix platforms; on Windows, they are only supported for short \
non-UNC file paths containing max 260 characters: <br>> +                 DON'T: self \
primLookupEntryIn: '<very long="" path="">\foo\.' index: ... <br>> +                 \
DON'T: self primLookupEntryIn: '<very long="" path="">\foo\..' index: ... <br>> +     \
DON'T (on Windows): self primLookupEntryIn: '<very long="" path="">\foo/bar' index: \
... <br>> +         See the comment in the primitive implementation for more details.
<br>> 
<br>>         The creation and modification times are in seconds since the start of \
the Smalltalk time epoch. DirFlag is true if the entry is a directory. FileSize the \
file size in bytes or zero for directories. The primitive returns nil when index is \
past the end of the directory. It fails if the given path is bad." <br>> 
<br>>         <primitive: 'primitivedirectorylookup'="" module:="" 'fileplugin'="">
<br>>         ^ #badDirectoryPath
<br>> 
<br>> 
<br>> 
<br>> FileDirectory>>primLookupEntryIn:name: {private}  · ct 8/17/2023 13:28 \
(changed) <br>> primLookupEntryIn: fullPath name: fName
<br>> - 
<br>>         "Look up <fname> (a simple file name) in the directory identified by \
<fullpath> <br>>          and return an array containing:
<br>> 
<br>>         <fname> <creationtime> <modificationtime> <dirflag> <filesize>
<br>> 
<br>>         On Unix, the empty path denotes '/'. 
<br>> On Macs and PCs, it is the container of the system volumes.)
<br>> +         Note that in general, neither fullPath nor fName must contain \
syntactic sugar for the current platform (e.g., '.' or '..', or on Windows, forward \
slashes instead of backslashes). These conventions are only fully supported on Unix \
platforms; on Windows, they are only supported for short non-UNC file paths \
containing max 260 characters (for the full path concatenated from the directory \
path, a backslash, and the file name). As a single (!) exception, the file name may \
always be a single dot ('.'), which is supported for an efficient existence test of \
the directory path (e.g., FileDirectory>>#exists): <br>> +                 DON'T: \
self primLookupEntryIn: '<very long="" path="">' name: 'plonk\.'. <br>> +             \
DON'T: self primLookupEntryIn: '<very long="" path="">' name: 'plonk\..'. <br>> +     \
DON'T (on Windows): self primLookupEntryIn: '<very long="" path="">' name: 'foo/bar'. \
<br>> +                 DO: self primLookupEntryIn: '<very long="" path="">' name: \
'.'. <br>> +         See the comment in the primitive implementation for more \
details. <br>> 
<br>>         The creation and modification times are in seconds since the start of \
the Smalltalk time epoch. DirFlag is true if the entry is a directory. FileSize the \
file size in bytes or zero for directories. The primitive returns nil when index is \
past the end of the directory. It fails if the given path is bad." <br>> 
<br>>         <primitive: 'primitivedirectoryentry'="" module:="" 'fileplugin'="">
<br>> 
<br>>         ^ #primFailed                "to distinguish from nil"
<br>> 
<br>> 
<br>> 
<br>> FilePlugin>>primitiveDirectoryEntry {directory primitives}  · ct 8/17/2023 \
13:28 (changed) <br>> primitiveDirectoryEntry
<br>> 
<br>>         "Two arguments - directory path, and simple file name;
<br>>          returns an array (see primitiveDirectoryLookup) describing the file or \
directory, <br>>          or nil if it does not exist. 
<br>> +          
<br>> +          Note that in general, the directory path name must not contain \
syntactic <br>> +          sugar for the current platform (e.g., '.' or '..', or on \
Windows, forward slashes <br>> +          instead of backslashes). These conventions \
are only fully supported on Unix <br>> +          platforms; on Windows, they are \
only supported for short non-UNC file paths <br>> +          containing max 260 \
characters (for the full path concatenated from the <br>> +          directory path, \
a backslash, and the file name): <br>> +                  DON'T: \
primitiveDirectoryEntry '<very long="" path="">\foo\.' ... <br>> +                  \
DON'T: primitiveDirectoryEntry '<very long="" path="">\foo\..' ... <br>> +            \
DON'T (on Windows): primitiveDirectoryEntry '<very long="" path="">\foo/bar' ... \
<br>> +          See the comment in sqWin32Directory.c for more details. <br>> +      \
 <br>>          Primitive fails if the outer path does not identify a readable \
directory. <br>>          (This is a lookup-by-name variant of \
primitiveDirectoryLookup.)" <br>> 
<br>>         | requestedName pathName pathNameIndex pathNameSize status entryName \
entryNameSize createDate modifiedDate dirFlag posixPermissions symlinkFlag fileSize \
okToList reqNameIndex reqNameSize | <br>>         
<br>>         <var: 'entryname'="" declarec:="" 'char="" entryname[256]'="">
<br>>         <var: 'pathnameindex'="" type:="" #'char="" *'="">
<br>>         <var: 'reqnameindex'="" type:="" #'char="" *'="">
<br>>         <var: 'filesize'="" type:="" #squeakfileoffsettype="">
<br>>         <export: true="">
<br>> 
<br>>         requestedName := interpreterProxy stackValue: 0.
<br>>         pathName := interpreterProxy stackValue: 1.
<br>>         (interpreterProxy isBytes: pathName) ifFalse:
<br>>                 [^interpreterProxy primitiveFail].
<br>> 
<br>>         "Outbound string parameters"
<br>>         pathNameIndex := interpreterProxy firstIndexableField: pathName.
<br>>         pathNameSize := interpreterProxy byteSizeOf: pathName.
<br>> 
<br>>         reqNameIndex := interpreterProxy firstIndexableField: requestedName.
<br>>         reqNameSize := interpreterProxy byteSizeOf: requestedName.
<br>>         self cCode: '' inSmalltalk:
<br>>                 [entryName := ByteString new: 256.
<br>>                  entryNameSize := createDate := modifiedDate := dirFlag := \
fileSize := posixPermissions := symlinkFlag := nil]. <br>>         "If the security \
plugin can be loaded, use it to check for permission.  <br>>          If not, assume \
it's ok" <br>>         okToList := sCLPfn ~= 0
<br>>                                         ifTrue: [self cCode: '((sqInt (*)(char \
*, sqInt))sCLPfn)(pathNameIndex, pathNameSize)' inSmalltalk: [true]] <br>>            \
ifFalse: [true]. <br>>         status := okToList
<br>>                 ifTrue:
<br>>                         [self dir_EntryLookup: pathNameIndex _: pathNameSize
<br>>                                         _: reqNameIndex _: reqNameSize
<br>>                                         _: entryName _: (self addressOf: \
entryNameSize put: [:v| entryNameSize := v]) <br>>                                    \
_: (self addressOf: createDate put: [:v| createDate := v]) <br>>                      \
_: (self addressOf: modifiedDate put: [:v| modifiedDate := v]) <br>>                  \
_: (self addressOf: dirFlag put: [:v| dirFlag := v]) <br>>                            \
_: (self addressOf: fileSize put: [:v| fileSize := v]) <br>>                          \
_: (self addressOf: posixPermissions put: [:v| posixPermissions := v]) <br>>          \
_: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])] <br>>                 \
ifFalse: <br>>                         [DirNoMoreEntries].
<br>> 
<br>>         interpreterProxy failed ifTrue:
<br>>                 [^nil].
<br>>         status = DirNoMoreEntries ifTrue: "no entry; return nil"
<br>>                 [interpreterProxy "pop pathName, index, rcvr"
<br>>                         pop: 3 thenPush: interpreterProxy nilObject.
<br>>                         ^nil].
<br>>         status = DirBadPath ifTrue:
<br>>                 [^interpreterProxy primitiveFail]."bad path"
<br>> 
<br>>         interpreterProxy 
<br>>                 pop: 3        "pop pathName, index, rcvr" 
<br>>                 thenPush:
<br>>                         (self 
<br>>                                 cppIf: PharoVM 
<br>>                                 ifTrue:
<br>>                                         [self
<br>>                                                 makeDirEntryName: entryName
<br>>                                                 size: entryNameSize
<br>>                                                 createDate: createDate
<br>>                                                 modDate: modifiedDate
<br>>                                                 isDir: dirFlag
<br>>                                                 fileSize: fileSize
<br>>                                                 posixPermissions: \
posixPermissions <br>>                                                 isSymlink: \
symlinkFlag] <br>>                                 ifFalse:
<br>>                                         [self
<br>>                                                 makeDirEntryName: entryName
<br>>                                                 size: entryNameSize
<br>>                                                 createDate: createDate
<br>>                                                 modDate: modifiedDate
<br>>                                                 isDir: dirFlag
<br>>                                                 fileSize: fileSize])
<br>> 
<br>> FilePlugin>>primitiveDirectoryLookup {directory primitives}  · ct 8/17/2023 \
13:30 (changed) <br>> primitiveDirectoryLookup
<br>> +         "Two arguments - directory path, and an index to an item; returns an \
array (see primitiveDirectoryLookup) describing the file or directory, or nil if it \
does not exist.  <br>> +         
<br>> +         Note that in general, the directory path must not contain syntactic \
sugar for the current platform (e.g., '.' or '..', or on Windows, forward slashes \
instead of backslashes). These conventions are only fully supported on Unix \
platforms; on Windows, they are only supported for short non-UNC file paths \
containing max 260 characters: <br>> +                 DON'T: \
primitiveDirectoryLookup '<very long="" path="">' 'foo\.' <br>> +                 \
DON'T: primitiveDirectoryLookup '<very long="" path="">' foo\..' <br>> +              \
DON'T (on Windows): primitiveDirectoryLookup '<very long="" path="">' 'foo/bar' <br>> \
+                 DO: primitiveDirectoryLookup '<very long="" path="">' '.' <br>> +   \
See the comment in sqWin32Directory.c for more details. <br>> +         
<br>> +         Primitive fails if the outer path does not identify a readable \
directory. (For a lookup-by-name variant, see primitiveDirectoryEntry.)" <br>> 
<br>>         | index pathName pathNameIndex pathNameSize status entryName \
entryNameSize createDate modifiedDate dirFlag symlinkFlag posixPermissions fileSize \
okToList | <br>>         
<br>>         <var: 'entryname'="" declarec:="" 'char="" entryname[256]'="">
<br>>         <var: 'pathnameindex'="" type:="" #'char="" *'="">
<br>>         <var: 'filesize'="" type:="" #squeakfileoffsettype="">
<br>>         <export: true="">
<br>> 
<br>>         index := interpreterProxy stackIntegerValue: 0.
<br>>         pathName := interpreterProxy stackValue: 1.
<br>>         (interpreterProxy isBytes: pathName)
<br>>                 ifFalse: [^interpreterProxy primitiveFail].
<br>>         pathNameIndex := interpreterProxy firstIndexableField: pathName.
<br>>         pathNameSize := interpreterProxy byteSizeOf: pathName.
<br>>         self cCode: '' inSmalltalk:
<br>>                 [entryName := ByteString new: 256.
<br>>                  entryNameSize := createDate := modifiedDate := dirFlag := \
fileSize := posixPermissions := symlinkFlag := nil]. <br>>         "If the security \
plugin can be loaded, use it to check for permission.  <br>>         If not, assume \
it's ok" <br>>         okToList := sCLPfn ~= 0
<br>>                                         ifTrue: [self cCode: '((sqInt (*)(char \
*, sqInt))sCLPfn)(pathNameIndex, pathNameSize)' inSmalltalk: [true]] <br>>            \
ifFalse: [true]. <br>>         status := okToList
<br>>                 ifTrue:
<br>>                         [self dir_Lookup: pathNameIndex _: pathNameSize
<br>>                                         _: index
<br>>                                         _: entryName _: (self addressOf: \
entryNameSize put: [:v| entryNameSize := v]) <br>>                                    \
_: (self addressOf: createDate put: [:v| createDate := v]) <br>>                      \
_: (self addressOf: modifiedDate put: [:v| modifiedDate := v]) <br>>                  \
_: (self addressOf: dirFlag put: [:v| dirFlag := v]) <br>>                            \
_: (self addressOf: fileSize put: [:v| fileSize := v]) <br>>                          \
_: (self addressOf: posixPermissions put: [:v| posixPermissions := v]) <br>>          \
_: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])] <br>>                 \
ifFalse: [DirNoMoreEntries]. <br>>         interpreterProxy failed ifTrue:
<br>>                 [^nil].
<br>>         status = DirNoMoreEntries ifTrue: "no more entries; return nil"
<br>>                 [interpreterProxy "pop pathName, index, rcvr"
<br>>                         pop: 3 thenPush: interpreterProxy nilObject.
<br>>                 ^nil].
<br>>         status = DirBadPath ifTrue:
<br>>                 [^interpreterProxy primitiveFail]."bad path"
<br>> 
<br>>         interpreterProxy 
<br>>                 pop: 3        "pop pathName, index, rcvr" 
<br>>                 thenPush:
<br>>                         (self 
<br>>                                 cppIf: PharoVM 
<br>>                                 ifTrue:
<br>>                                         [self
<br>>                                                 makeDirEntryName: entryName
<br>>                                                 size: entryNameSize
<br>>                                                 createDate: createDate
<br>>                                                 modDate: modifiedDate
<br>>                                                 isDir: dirFlag
<br>>                                                 fileSize: fileSize
<br>>                                                 posixPermissions: \
posixPermissions <br>>                                                 isSymlink: \
symlinkFlag] <br>>                                 ifFalse:
<br>>                                         [self
<br>>                                                 makeDirEntryName: entryName
<br>>                                                 size: entryNameSize
<br>>                                                 createDate: createDate
<br>>                                                 modDate: modifiedDate
<br>>                                                 isDir: dirFlag
<br>>                                                 fileSize: fileSize])
<br>> 
<br>> ---
<br>> Sent from Squeak Inbox Talk
<br>> ["noUNCPaths.4.cs"]
<br>> 
<br>> On 2022-11-30T07:16:49-08:00, eliot.miranda(a)gmail.com wrote:
<br>> 
<br>> > Oops! I see you did cc. I should stop reading email in my phone. The \
letterbox is too small. <br>> > 
<br>> > _,,,^..^,,,_ (phone)
<br>> > 
<br>> > > On Nov 30, 2022, at 7:16 AM, Eliot Miranda <eliot.miranda at="" \
gmail.com=""> wrote: <br>> > > 
<br>> > > Hi Christoph,
<br>> > > 
<br>> > > looks good. Please cc messages like this which are relevant to the vm to \
vm-dev (aka opensmalltalk-vm). I would love to see some example paths in the comments \
below rather than just "don't include ‘..' ‘.'). Show a path that would be \
converted to unc path vs a proper windows path. People coming to the vm may not have \
experience with all platforms. Over commenting is a much better evil than \
overcommenting :-) <br>> > > 
<br>> > > Sorry for top posting
<br>> > > _,,,^..^,,,_ (phone)
<br>> > > 
<br>> > >>> On Nov 30, 2022, at 6:58 AM, Christoph.Thiede at \
student.hpi.uni-potsdam.de wrote: <br>> > >>> 
<br>> > >> Repairs FileDirectory>>#exists for long paths (> 260 characters) on \
Windows by well-defining an edge case in the Windows implementation of the FilePlugin \
primitiveDirectoryEntry, that is, to specify a single dot (.) as the file name. \
Documents the present limitations to syntactic sugar in long file paths in the \
platform code, the relevant plugin methods, and on the image side of Squeak Trunk. \
<br>> > >>  <br>> > >> An alternative consideration was to rewrite \
FileDirectory>>#exists to pass an empty string as file name to the primitive instead \
of modifying the VM, but strictly speaking, even this would have exploited an \
undefined behavior in the VM plugin, and an empty file name would be less idiomatic \
than a single dot. <br>> > >> 
<br>> > >> For the original bug report, see: \
https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 Thanks to \
Marcel (mt) for his support! <br>> > >> 
<br>> > >> Signed-off-by: Christoph Thiede <christoph.thiede at="" student.hpi.de="">
<br>> > >> ---
<br>> > >> Note that this mail contains both a git diff for the changes in the \
opensmalltalk-vm repository and a changeset for the changes in the Squeak Trunk so \
that they may be reviewed together. Any feedback on this formatting approach will be \
appreciated. Excited to receive your review! <br>> > >> 
<br>> > >> platforms/win32/vm/sqWin32Directory.c | 29 +++++++++++++++++++++++++++
<br>> > >> 1 file changed, 29 insertions(+)
<br>> > >> 
<br>> > >> diff --git a/platforms/win32/vm/sqWin32Directory.c \
b/platforms/win32/vm/sqWin32Directory.c <br>> > >> index 2b3d090ec..0aa5c2108 100644
<br>> > >> --- a/platforms/win32/vm/sqWin32Directory.c
<br>> > >> +++ b/platforms/win32/vm/sqWin32Directory.c
<br>> > >> @@ -196,6 +196,15 @@ sqInt dir_Lookup(char *pathString, sqInt pathLength, \
sqInt index, <br>> > >> /* Lookup the index-th entry of the directory with the given \
path, starting <br>> > >> at the root of the file system. Set the name, name length, \
creation date, <br>> > >> creation time, directory flag, and file size (if the entry \
is a file). <br>> > >> +
<br>> > >> + Note that, due to restrictions by the operating system, this method only
<br>> > >> + has limited support for paths longer than 260 characters. In the case of
<br>> > >> + longer paths, they must not contain syntactic sugar such as ".", "..", \
or <br>> > >> + "a/b".* For more details, see:
<br>> > >> + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
 <br>> > >> + *) Long paths are automatically converted into UNC paths, which only
<br>> > >> + support a subset of the normal path syntax.
<br>> > >> +
<br>> > >> Return:
<br>> > >> 0 if a entry is found at the given index
<br>> > >> 1 if the directory has fewer than index entries
<br>> > >> @@ -354,6 +363,20 @@ sqInt dir_EntryLookup(char *pathString, sqInt \
pathLength, char* nameString, sqIn <br>> > >> /* Lookup a given file in a given named \
directory. <br>> > >> Set the name, name length, creation date,
<br>> > >> creation time, directory flag, and file size (if the entry is a file).
<br>> > >> +
<br>> > >> + Note that, due to restrictions by the operating system, this method only
<br>> > >> + has limited support for paths longer than 260 characters (for the full
<br>> > >> + path concatenated from the directory path, a backslash, and the file
<br>> > >> + name). In the case of longer paths, neither the path nor the file name
<br>> > >> + must contain syntactic sugar such as ".", "..", or "a/b".* However, this
<br>> > >> + method defines a single (!) convention for passing nameString as ".",
<br>> > >> + which is also supported for long paths. This convention is provided for
<br>> > >> + an efficient existence check of the directory (e.g.,
<br>> > >> + FileDirectory>>#exists). For more details, see:
<br>> > >> + https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#paths
 <br>> > >> + *) Long paths are automatically converted into UNC paths, which only
<br>> > >> + support a subset of the normal path syntax.
<br>> > >> +
<br>> > >> Return:
<br>> > >> 0 if found (a file or directory 'nameString' exists in directory \
'pathString') <br>> > >> 1 if the directory has no such entry
<br>> > >> @@ -416,6 +439,12 @@ sqInt dir_EntryLookup(char *pathString, sqInt \
pathLength, char* nameString, sqIn <br>> > >> fullPath=(char \
*)calloc(fullPathLength,sizeof(char)); <br>> > >> \
memcpy(fullPath,pathString,pathLength); <br>> > >> if (pathString[pathLength-1] != \
'\\') fullPath[pathLength]='\\'; <br>> > >> + if (nameStringLength == 1 && \
nameString[0] == '.') { <br>> > >> + /* special syntax: "." is the current directory. \
Trim it from the full <br>> > >> + path to avoid generating a UNC path with an \
unresolved ".", which is <br>> > >> + not supported there. See comment above. */
<br>> > >> + nameStringLength = 0;
<br>> > >> + }
<br>> > >> memcpy(fullPath+fullPathLength-nameStringLength,nameString,nameStringLength);
 <br>> > >> 
<br>> > >> /* convert the path name into a null-terminated C string */
<br>> > >> -- 
<br>> > >> 2.37.3.windows.1
<br>> > >> 
<br>> > >> =============== Summary ===============
<br>> > >> 
<br>> > >> Change Set: noUNCPaths
<br>> > >> Date: 30 November 2022
<br>> > >> Author: Christoph Thiede
<br>> > >> 
<br>> > >> Documents the present limitations to syntactic sugar in long file paths in \
the relevant plugin methods and on the image side. <br>> > >> 
<br>> > >> For the original bug report, see: \
https://github.com/hpi-swa-teaching/Morphic-Testing-Framework/issues/13 Thanks to \
Marcel (mt) for his support! <br>> > >> 
<br>> > >> =============== Diff ===============
<br>> > >> 
<br>> > >> FileDirectory>>primLookupEntryIn:index: {private}  · ct 11/29/2022 20:24 \
(changed) <br>> > >> primLookupEntryIn: fullPath index: index
<br>> > >> "Look up the index-th entry of the directory with the given \
fully-qualified path (i.e., starting from the root of the file hierarchy) and return \
an array containing: <br>> > >> 
<br>> > >> <name> <creationtime> <modificationtime> <dirflag> <filesize>
<br>> > >> 
<br>> > >> The empty string enumerates the top-level files or drives. (For example, \
on Unix, the empty path enumerates the contents of '/'. On Macs and PCs, it \
enumerates the mounted volumes/drives.) <br>> > >> + Note that in general, fullPath \
must not contain syntactic sugar for the current platform (e.g., '.' or '..', or on \
Windows, forward slashes instead of backslashes). These conventions are only fully \
supported on Unix platforms; on Windows, they are only supported for short non-UNC \
file paths containing max 260 characters. See the comment in the primitive \
implementation for more details. <br>> > >> 
<br>> > >> The creation and modification times are in seconds since the start of the \
Smalltalk time epoch. DirFlag is true if the entry is a directory. FileSize the file \
size in bytes or zero for directories. The primitive returns nil when index is past \
the end of the directory. It fails if the given path is bad." <br>> > >> 
<br>> > >> <primitive: 'primitivedirectorylookup'="" module:="" 'fileplugin'="">
<br>> > >> ^ #badDirectoryPath
<br>> > >> 
<br>> > >> 
<br>> > >> 
<br>> > >> FileDirectory>>primLookupEntryIn:name: {private}  · ct 11/30/2022 15:38 \
(changed) <br>> > >> primLookupEntryIn: fullPath name: fName
<br>> > >> - 
<br>> > >> "Look up <fname> (a simple file name) in the directory identified by \
<fullpath> <br>> > >> and return an array containing:
<br>> > >> 
<br>> > >> <fname> <creationtime> <modificationtime> <dirflag> <filesize>
<br>> > >> 
<br>> > >> On Unix, the empty path denotes '/'. 
<br>> > >> On Macs and PCs, it is the container of the system volumes.)
<br>> > >> + Note that in general, neither fullPath nor fName must contain syntactic \
sugar for the current platform (e.g., '.' or '..', or on Windows, forward slashes \
instead of backslashes). These conventions are only fully supported on Unix \
platforms; on Windows, they are only supported for short non-UNC file paths \
containing max 260 characters (for the full path concatenated from the directory \
path, a backslash, and the file name). As a single (!) exception, the file name may \
always be a single dot ('.'), which is supported for an efficient existence test of \
the directory path (e.g., FileDirectory>>#exists). See the comment in the primitive \
implementation for more details. <br>> > >> 
<br>> > >> The creation and modification times are in seconds since the start of the \
Smalltalk time epoch. DirFlag is true if the entry is a directory. FileSize the file \
size in bytes or zero for directories. The primitive returns nil when index is past \
the end of the directory. It fails if the given path is bad." <br>> > >> 
<br>> > >> <primitive: 'primitivedirectoryentry'="" module:="" 'fileplugin'="">
<br>> > >> 
<br>> > >> ^ #primFailed "to distinguish from nil"
<br>> > >> 
<br>> > >> 
<br>> > >> 
<br>> > >> FilePlugin>>primitiveDirectoryEntry {directory primitives}  · ct \
11/30/2022 15:13 (changed) <br>> > >> primitiveDirectoryEntry
<br>> > >> 
<br>> > >> "Two arguments - directory path, and simple file name;
<br>> > >> returns an array (see primitiveDirectoryLookup) describing the file or \
directory, <br>> > >> or nil if it does not exist. 
<br>> > >> + 
<br>> > >> + Note that in general, neither the directory path nor the file name must
<br>> > >> + contain syntactic sugar for the current platform (e.g., '.' or '..', or \
on <br>> > >> + Windows, forward slashes instead of backslashes). These conventions \
are <br>> > >> + only fully supported on Unix platforms; on Windows, they are only
<br>> > >> + supported for short non-UNC file paths containing max 260 characters \
(for <br>> > >> + the full path concatenated from the directory path, a backslash, \
and the <br>> > >> + file name). As a single (!) exception, the file name may always \
be a <br>> > >> + single dot ('.'), which is supported for an efficient existence \
test of <br>> > >> + the directory path (e.g., FileDirectory>>#exists). See the \
comment in <br>> > >> + sqWin32Directory.c for more details.
<br>> > >> + 
<br>> > >> Primitive fails if the outer path does not identify a readable directory.
<br>> > >> (This is a lookup-by-name variant of primitiveDirectoryLookup.)"
<br>> > >> 
<br>> > >> | requestedName pathName pathNameIndex pathNameSize status entryName \
entryNameSize createDate modifiedDate dirFlag posixPermissions symlinkFlag fileSize \
okToList reqNameIndex reqNameSize | <br>> > >> 
<br>> > >> <var: 'entryname'="" declarec:="" 'char="" entryname[256]'="">
<br>> > >> <var: 'pathnameindex'="" type:="" #'char="" *'="">
<br>> > >> <var: 'reqnameindex'="" type:="" #'char="" *'="">
<br>> > >> <var: 'filesize'="" type:="" #squeakfileoffsettype="">
<br>> > >> <export: true="">
<br>> > >> 
<br>> > >> requestedName := interpreterProxy stackValue: 0.
<br>> > >> pathName := interpreterProxy stackValue: 1.
<br>> > >> (interpreterProxy isBytes: pathName) ifFalse:
<br>> > >> [^interpreterProxy primitiveFail].
<br>> > >> 
<br>> > >> "Outbound string parameters"
<br>> > >> pathNameIndex := interpreterProxy firstIndexableField: pathName.
<br>> > >> pathNameSize := interpreterProxy byteSizeOf: pathName.
<br>> > >> 
<br>> > >> reqNameIndex := interpreterProxy firstIndexableField: requestedName.
<br>> > >> reqNameSize := interpreterProxy byteSizeOf: requestedName.
<br>> > >> self cCode: '' inSmalltalk:
<br>> > >> [entryName := ByteString new: 256.
<br>> > >> entryNameSize := createDate := modifiedDate := dirFlag := fileSize := \
posixPermissions := symlinkFlag := nil]. <br>> > >> "If the security plugin can be \
loaded, use it to check for permission.  <br>> > >> If not, assume it's ok"
<br>> > >> okToList := sCLPfn ~= 0
<br>> > >> ifTrue: [self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, \
pathNameSize)' inSmalltalk: [true]] <br>> > >> ifFalse: [true].
<br>> > >> status := okToList
<br>> > >> ifTrue:
<br>> > >> [self dir_EntryLookup: pathNameIndex _: pathNameSize
<br>> > >> _: reqNameIndex _: reqNameSize
<br>> > >> _: entryName _: (self addressOf: entryNameSize put: [:v| entryNameSize := \
v]) <br>> > >> _: (self addressOf: createDate put: [:v| createDate := v])
<br>> > >> _: (self addressOf: modifiedDate put: [:v| modifiedDate := v])
<br>> > >> _: (self addressOf: dirFlag put: [:v| dirFlag := v])
<br>> > >> _: (self addressOf: fileSize put: [:v| fileSize := v])
<br>> > >> _: (self addressOf: posixPermissions put: [:v| posixPermissions := v])
<br>> > >> _: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])]
<br>> > >> ifFalse:
<br>> > >> [DirNoMoreEntries].
<br>> > >> 
<br>> > >> interpreterProxy failed ifTrue:
<br>> > >> [^nil].
<br>> > >> status = DirNoMoreEntries ifTrue: "no entry; return nil"
<br>> > >> [interpreterProxy "pop pathName, index, rcvr"
<br>> > >> pop: 3 thenPush: interpreterProxy nilObject.
<br>> > >> ^nil].
<br>> > >> status = DirBadPath ifTrue:
<br>> > >> [^interpreterProxy primitiveFail]."bad path"
<br>> > >> 
<br>> > >> interpreterProxy 
<br>> > >> pop: 3 "pop pathName, index, rcvr" 
<br>> > >> thenPush:
<br>> > >> (self 
<br>> > >> cppIf: PharoVM 
<br>> > >> ifTrue:
<br>> > >> [self
<br>> > >> makeDirEntryName: entryName
<br>> > >> size: entryNameSize
<br>> > >> createDate: createDate
<br>> > >> modDate: modifiedDate
<br>> > >> isDir: dirFlag
<br>> > >> fileSize: fileSize
<br>> > >> posixPermissions: posixPermissions
<br>> > >> isSymlink: symlinkFlag]
<br>> > >> ifFalse:
<br>> > >> [self
<br>> > >> makeDirEntryName: entryName
<br>> > >> size: entryNameSize
<br>> > >> createDate: createDate
<br>> > >> modDate: modifiedDate
<br>> > >> isDir: dirFlag
<br>> > >> fileSize: fileSize])
<br>> > >> 
<br>> > >> FilePlugin>>primitiveDirectoryLookup {directory primitives}  · ct \
11/30/2022 15:00 (changed) <br>> > >> primitiveDirectoryLookup
<br>> > >> + "Two arguments - directory path, and an index to an item; returns an \
array (see primitiveDirectoryLookup) describing the file or directory, or nil if it \
does not exist.  <br>> > >> + 
<br>> > >> + Note that in general, the directory path must not contain syntactic \
sugar for the current platform (e.g., '.' or '..', or on Windows, forward slashes \
instead of backslashes). These conventions are only fully supported on Unix \
platforms; on Windows, they are only supported for short non-UNC file paths \
containing max 260 characters. See the comment in sqWin32Directory.c for more \
details. <br>> > >> + 
<br>> > >> + Primitive fails if the outer path does not identify a readable \
directory. (For a lookup-by-name variant, see primitiveDirectoryEntry.)" <br>> > >> 
<br>> > >> | index pathName pathNameIndex pathNameSize status entryName entryNameSize \
createDate modifiedDate dirFlag symlinkFlag posixPermissions fileSize okToList | \
<br>> > >>  <br>> > >> <var: 'entryname'="" declarec:="" 'char="" entryname[256]'="">
<br>> > >> <var: 'pathnameindex'="" type:="" #'char="" *'="">
<br>> > >> <var: 'filesize'="" type:="" #squeakfileoffsettype="">
<br>> > >> <export: true="">
<br>> > >> 
<br>> > >> index := interpreterProxy stackIntegerValue: 0.
<br>> > >> pathName := interpreterProxy stackValue: 1.
<br>> > >> (interpreterProxy isBytes: pathName)
<br>> > >> ifFalse: [^interpreterProxy primitiveFail].
<br>> > >> pathNameIndex := interpreterProxy firstIndexableField: pathName.
<br>> > >> pathNameSize := interpreterProxy byteSizeOf: pathName.
<br>> > >> self cCode: '' inSmalltalk:
<br>> > >> [entryName := ByteString new: 256.
<br>> > >> entryNameSize := createDate := modifiedDate := dirFlag := fileSize := \
posixPermissions := symlinkFlag := nil]. <br>> > >> "If the security plugin can be \
loaded, use it to check for permission.  <br>> > >> If not, assume it's ok"
<br>> > >> okToList := sCLPfn ~= 0
<br>> > >> ifTrue: [self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, \
pathNameSize)' inSmalltalk: [true]] <br>> > >> ifFalse: [true].
<br>> > >> status := okToList
<br>> > >> ifTrue:
<br>> > >> [self dir_Lookup: pathNameIndex _: pathNameSize
<br>> > >> _: index
<br>> > >> _: entryName _: (self addressOf: entryNameSize put: [:v| entryNameSize := \
v]) <br>> > >> _: (self addressOf: createDate put: [:v| createDate := v])
<br>> > >> _: (self addressOf: modifiedDate put: [:v| modifiedDate := v])
<br>> > >> _: (self addressOf: dirFlag put: [:v| dirFlag := v])
<br>> > >> _: (self addressOf: fileSize put: [:v| fileSize := v])
<br>> > >> _: (self addressOf: posixPermissions put: [:v| posixPermissions := v])
<br>> > >> _: (self addressOf: symlinkFlag put: [:v| symlinkFlag := v])]
<br>> > >> ifFalse: [DirNoMoreEntries].
<br>> > >> interpreterProxy failed ifTrue:
<br>> > >> [^nil].
<br>> > >> status = DirNoMoreEntries ifTrue: "no more entries; return nil"
<br>> > >> [interpreterProxy "pop pathName, index, rcvr"
<br>> > >> pop: 3 thenPush: interpreterProxy nilObject.
<br>> > >> ^nil].
<br>> > >> status = DirBadPath ifTrue:
<br>> > >> [^interpreterProxy primitiveFail]."bad path"
<br>> > >> 
<br>> > >> interpreterProxy 
<br>> > >> pop: 3 "pop pathName, index, rcvr" 
<br>> > >> thenPush:
<br>> > >> (self 
<br>> > >> cppIf: PharoVM 
<br>> > >> ifTrue:
<br>> > >> [self
<br>> > >> makeDirEntryName: entryName
<br>> > >> size: entryNameSize
<br>> > >> createDate: createDate
<br>> > >> modDate: modifiedDate
<br>> > >> isDir: dirFlag
<br>> > >> fileSize: fileSize
<br>> > >> posixPermissions: posixPermissions
<br>> > >> isSymlink: symlinkFlag]
<br>> > >> ifFalse:
<br>> > >> [self
<br>> > >> makeDirEntryName: entryName
<br>> > >> size: entryNameSize
<br>> > >> createDate: createDate
<br>> > >> modDate: modifiedDate
<br>> > >> isDir: dirFlag
<br>> > >> fileSize: fileSize])
<br>> > >> 
<br>> > >> ---
<br>> > >> Sent from Squeak Inbox Talk
<br>> > >> ["noUNCPaths.3.cs"]
<br>> > > 
<br>> > >>
<br>
<br></export:></var:></var:></var:></export:></var:></var:></var:></var:></primitive:> \
</filesize></dirflag></modificationtime></creationtime></fname></fullpath></fname></pr \
imitive:></filesize></dirflag></modificationtime></creationtime></name></christoph.thi \
ede></eliot.miranda></export:></var:></var:></var:></very></very></very></very></expor \
t:></var:></var:></var:></var:></very></very></very></primitive:></very></very></very> \
</very></filesize></dirflag></modificationtime></creationtime></fname></fullpath></fna \
me></primitive:></very></very></very></filesize></dirflag></modificationtime></creatio \
ntime></name></very></very></very></very></very></very></very></div></blockquote>  \
</div></body>





[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic