Eliot Miranda uploaded a new version of FileAttributesPlugin to project VM Maker: http://source.squeak.org/VMMaker/FileAttributesPlugin.oscog-AlistairGrant.40.mcz ==================== Summary ==================== Name: FileAttributesPlugin.oscog-AlistairGrant.40 Author: AlistairGrant Time: 6 October 2018, 8:10:27.610572 pm UUID: 2d975e6c-81fb-4b6d-9dab-35be5e978e22 Ancestors: FileAttributesPlugin.oscog-AlistairGrant.39 FileAttributesPlugin 2.0.2: free faPath It's too easy to forget that C doesn't have garbage collection, especially in slang... :-) =============== Diff against FileAttributesPlugin.oscog-AlistairGrant.28 =============== Item was changed: ----- Method: FileAttributesPlugin class>>declareCVarsIn: (in category 'translation') ----- declareCVarsIn: cg self declareC: #('sCLPfn' 'sCOFfn') as: #'void *' in: cg. "Assume the security plugin can be loaded until proven otherwise" cg var: 'hasSecurityPlugin' declareC: 'int hasSecurityPlugin = 1'. + cg addHeaderFile: '<errno.h>'. cg addHeaderFile: '<limits.h>'. cg addHeaderFile: '<sys/types.h>'. + cg addHeaderFile: '<unistd.h>'. cg addHeaderFile: '<dirent.h> + #if _WIN32 || _WIN64 + # include <windows.h> + # include <winbase.h> + # define FAIL() { return -1; } + # include "sqWin32File.h" + # if !!defined(PATH_MAX) /* work around bug in 64-bit cygwin; sigh :-( */ + # define PATH_MAX 4096 + # endif + # define HAVE_CHMOD 0 + # define HAVE_CHOWN 0 + #else + #define HAVE_CHMOD 1 + #define HAVE_CHOWN 1 + #endif'. + cg addHeaderFile: '"faCommon.h"'. - #ifdef _WIN32 - #include <windows.h> - #include <winbase.h> - #define FAIL() { return -1; } - #include "sqWin32File.h" - #endif - typedef struct dirptrstruct { - DIR *dp; - int path_len; - char *path_file; - char path[PATH_MAX+4]; - } osdir;'. cg addHeaderFile: '<sys/stat.h> + #if !!defined(HAVE_LSTAT) && !!defined(_WIN32) && !!defined(_WIN64) + # define HAVE_LSTAT 1 - #if !!defined(HAVE_LSTAT) && !!defined(_WIN32) - #define HAVE_LSTAT 1 #endif'. cg addHeaderFile: '<unistd.h> + /* AKG 2018 - ', self moduleName, '.c translated from class ', self name, ' */'! - /* AKG 2017 - ', self moduleName, '.c translated from class ', self name, ' */'! Item was added: + ----- Method: FileAttributesPlugin class>>primFileAttributeOf:number: (in category 'testing') ----- + primFileAttributeOf: pathString number: attributeNumber + "Answer a single file attribute. + pathString is the path to the file + attributeNumber identifies which attribute to return: + 1 - 12: stat(): name, mode, ino, dev, nlink, uid, gid, size, accessDate, modifiedDate, changeDate, creationDate + 13 - 15: access(): R_OK, W_OK, X_OK + 16: isSymlink + On error, fail with an error code containing the appropriate OS error code." + + "(1 to: 16) collect: [:i| self primFileAttributeOf: '.' number: i]" + "(1 to: 16) collect: [:i| self primFileAttributeOf: 'THIS HAS A GOOD CHANCE OF FAILING' number: i]" + + <primitive: 'primitiveFileAttribute' module: 'FileAttributesPlugin' error: ec> + ^self primitiveFailed! Item was added: + ----- Method: FileAttributesPlugin class>>primFileAttributes:attributeNumber: (in category 'testing') ----- + primFileAttributes: pathString attributeNumber: attributeNumber + "Answer a single file attribute. + primFileAttributes: aString attributeNumber: attributeNumber + pathString is the path to the file + attributeNumber identifies which attribute to return: + 1 - 12: stat(): name, mode, ino, dev, nlink, uid, gid, size, accessDate, modifiedDate, changeDate, creationDate + 13 - 15: access(): R_OK, W_OK, X_OK + 16: isSymlink + On error, fail with an error code containing the appropriate OS error code." + + "(1 to: 16) collect: [:i| self installedFileAttributeFor: '.' numbered: i]" + "(1 to: 16) collect: [:i| self installedFileAttributeFor: 'THIS HAS A GOOD CHANCE OF FAILING' numbered: i]" + + <primitive: 'primitiveFileAttribute' module: 'FileAttributesPlugin' error: ec> + ^self primitiveFailed! Item was removed: - ----- Method: FileAttributesPlugin>>accessAttributesForFilename:into:startingAt: (in category 'private - file') ----- - accessAttributesForFilename: cPathName into: attributeArray startingAt: offset - "Call access() for each access type (R, W, X) on the c string cPathName, storing the results in the st array attributeArray." - - | index boolean | - <var: 'cPathName' type: 'char *'> - index := offset. - ((self acc: cPathName ess: self fileReadableFlag) = 0) - ifTrue: [boolean := interpreterProxy trueObject] - ifFalse: [boolean := interpreterProxy falseObject]. - interpreterProxy - storePointer: index - ofObject: attributeArray - withValue: boolean. - index := index + 1. - boolean := ((self acc: cPathName ess: self fileWriteableFlag) = 0) - ifTrue: [interpreterProxy trueObject] - ifFalse: [interpreterProxy falseObject]. - interpreterProxy - storePointer: index - ofObject: attributeArray - withValue: boolean. - index := index + 1. - boolean := ((self acc: cPathName ess: self fileExecutableFlag) = 0) - ifTrue: [interpreterProxy trueObject] - ifFalse: [interpreterProxy falseObject]. - interpreterProxy - storePointer: index - ofObject: attributeArray - withValue: boolean. - ! Item was changed: ----- Method: FileAttributesPlugin>>addressObjectFor: (in category 'private - directory') ----- addressObjectFor: aMachineAddress "Answer an ExternalAddress object which represents aMachineAddress" | addressOop addressOopArrayPointer addressUnion idx | + <var: 'aMachineAddress' type: #'void *'> + <var: 'addressUnion' type: 'union {void *address; unsigned char bytes[sizeof(void *)];}'> + <var: 'addressOopArrayPointer' type: #'unsigned char *'> + self touch: addressUnion. - <var: 'aMachineAddress' type: 'void *'> - <var: 'addressUnion' declareC: 'union {void *address; unsigned char bytes[sizeof(void *)];} addressUnion'> - <var: 'addressOopArrayPointer' declareC: 'unsigned char *addressOopArrayPointer'> addressOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self sizeOfPointer. addressOop ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. addressOopArrayPointer := interpreterProxy arrayValueOf: addressOop. self cCode: 'addressUnion.address = aMachineAddress'. idx := 0. [idx < self sizeOfPointer] whileTrue: [self cCode: 'addressOopArrayPointer[idx] = addressUnion.bytes[idx]'. idx := idx + 1]. ^ addressOop ! Item was removed: - ----- Method: FileAttributesPlugin>>byteArrayFromCString:to: (in category 'private') ----- - byteArrayFromCString: aCString to: byteArrayOop - "Answer a new ByteArray copied from a null-terminated C string. - Caution: This may invoke the garbage collector." - - | len newByteArray byteArrayPtr | - <var: 'aCString' type: 'const char *'> - <var: 'byteArrayPtr' type: 'unsigned char *'> - <var: 'byteArrayOop' type: 'sqInt *'> - len := self strlen: aCString. - "We never return strings longer than PATH_MAX" - len > #PATH_MAX ifTrue: [^self stringTooLong]. - newByteArray := interpreterProxy - instantiateClass: interpreterProxy classByteArray - indexableSize: len. - newByteArray ifNil: - [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. - byteArrayPtr := interpreterProxy arrayValueOf: newByteArray. - self mem: byteArrayPtr cp: aCString y: len. - byteArrayOop at: 0 put: newByteArray. - ^0! Item was changed: ----- Method: FileAttributesPlugin>>canOpenDirectoryStreamFor:length: (in category 'private - directory') ----- canOpenDirectoryStreamFor: aPathCString length: length "Answer non-zero if security permits the directory to be listed." "FIXME: This function has not been tested. -dtl" + <var: 'aPathCString' type: #'char *'> - <var: 'aPathCString' type: 'char *'> "If the security plugin can be loaded, use it to check . If not, assume it's ok" "The hasSecurityPlugin flag is set to 1 by default" (hasSecurityPlugin = 0) ifTrue: [^ true]. sCLPfn ~= 0 ifTrue: [^ self cCode: ' ((int (*) (char *, int)) sCLPfn)(aPathCString, length)' inSmalltalk: [true]] ifFalse: [hasSecurityPlugin := 0. "Reset the flag so we do not try again next time" ^ true] ! Item was changed: ----- Method: FileAttributesPlugin>>canStatFilePath:length: (in category 'private - file') ----- canStatFilePath: aPathCString length: length "Answer non-zero if security permits the a stat() call on the file path. Allow a stat() call only on files which we are permitted to open." "FIXME: This function has not been tested. -dtl" + <var: 'aPathCString' type: #'char *'> - <var: 'aPathCString' type: 'char *'> "If the security plugin can be loaded, use it to check . If not, assume it's ok" "The hasSecurityPlugin flag is set to 1 by default" (hasSecurityPlugin = 0) ifTrue: [^ true]. sCOFfn ~= 0 ifTrue: [^ self cCode: ' ((int (*) (char *, int, int)) sCOFfn)(aPathCString, length, 0)' inSmalltalk: [true]] ifFalse: [hasSecurityPlugin := 0. "Reset the flag so we do not try again next time" ^ true] ! Item was changed: + ----- Method: FileAttributesPlugin>>cantAllocateMemory (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>cantAllocateMemory (in category 'errors') ----- cantAllocateMemory <inline: #always> ^-10! Item was changed: + ----- Method: FileAttributesPlugin>>cantOpenDir (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>cantOpenDir (in category 'errors') ----- cantOpenDir <inline: #always> ^-9! Item was changed: + ----- Method: FileAttributesPlugin>>cantReadlink (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>cantReadlink (in category 'errors') ----- cantReadlink <inline: #always> ^-8! Item was changed: + ----- Method: FileAttributesPlugin>>cantStatPath (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>cantStatPath (in category 'errors') ----- cantStatPath "SecurityPlugin determined that the requested path cannot be accessed." <inline: #always> ^-3! Item was removed: - ----- Method: FileAttributesPlugin>>checkAccess:mode:to: (in category 'private - file') ----- - checkAccess: pathString mode: mode to: flag - "Check access to pathString." - - | cString len sPtr | - <export: true> - <var: 'cString' declareC: 'char cString[PATH_MAX]'> - <var: 'sPtr' declareC: 'char *sPtr'> - <var: 'flag' type: 'sqInt *'> - len := interpreterProxy stSizeOf: pathString. - "Note: The static sized string buffer is faster than using a Smalltalk allocated - string as the buffer, and is unlikely to fail in practice. In the event that - the buffer turns out to be too small, write an error message to stdout before - failing." - len >= #PATH_MAX ifTrue: [^self stringTooLong]. - "Copy pathString to the new string" - sPtr := interpreterProxy arrayValueOf: pathString. - ((self canStatFilePath: sPtr length: len) = 0) ifTrue: [^self cantStatPath]. - self mem: cString cp: sPtr y: len. - cString at: len put: 0. - flag at: 0 put: (self acc: cString ess: mode). - ^0 - ! Item was added: + ----- Method: FileAttributesPlugin>>convertWinToSqueakTime: (in category 'private - windows') ----- + convertWinToSqueakTime: st + "Convert the supplied Windows SYSTEMTIME to Squeak time" + <option: #_WIN32> + + | dy secs nDaysPerMonth | + + <returnTypeC: #'sqLong'> + <var: 'st' type: #'SYSTEMTIME'> + <var: 'dy' type: #'sqLong'> + <var: 'secs' type: #'sqLong'> + <var: 'nDaysPerMonth' declareC: 'static sqLong nDaysPerMonth[14] = { + 0, 0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334, 365 }'> + self touch: nDaysPerMonth. + + "Squeak epoch is Jan 1, 1901" + "compute delta year" + dy := (self cCode: 'st.wYear') - 1901. + secs := (dy * 365 * 24 * 60 * 60) "base seconds" + + ((dy bitShift: -2) * 24 * 60 * 60). "seconds of leap years" + "check if month > 2 and current year is a leap year" + [ (self cCode: 'st.wMonth') > 2 and: [ (dy bitAnd: 16r0003) = 16r0003 ]] ifTrue: [ + "add one day" + secs := secs + (24 * 60 * 60) ]. + "add the days from the beginning of the year" + secs := secs + (self cCode: '(nDaysPerMonth[st.wMonth] + st.wDay - 1) * 24 * 60 * 60'). + "add the hours, minutes, and seconds" + secs := secs + (self cCode: 'st.wSecond + 60*(st.wMinute + 60*st.wHour)'). + ^secs + ! Item was changed: + ----- Method: FileAttributesPlugin>>corruptValue (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>corruptValue (in category 'errors') ----- corruptValue <inline: #always> ^-7! Item was removed: - ----- Method: FileAttributesPlugin>>fileCreationTimeFor:length:to: (in category 'private - windows') ----- - fileCreationTimeFor: pathString length: pathLength to: creationDate - "Get the creationDate for the supplied file. - Linux kernel 4.11 should have statx(), so hopefully there will be a cross-platform - solution soon. Just dump the c-code and hope to remove it soon." - <option: #_WIN32> - | tm winAttrs win32Path sysTime | - <var: 'pathString' type: 'char *'> - <var: 'creationDate' type: 'time_t *'> - <var: 'tm' type: 'struct tm'> - <var: 'winAttrs' type: 'WIN32_FILE_ATTRIBUTE_DATA'> - <var: 'win32Path' type: 'WCHAR *'> - <var: 'sysTime' type: 'SYSTEMTIME'> - self touch: winAttrs. - self touch: sysTime. - self me: (self addressOf: tm) ms: 0 et: tm sizeof. - "convert the supplied path name into a wide string" - self ALLOC_: win32Path WIN32_: pathString PATH: pathLength. - (self cCode: 'GetFileAttributesExW(win32Path, 0, &winAttrs)') = 0 ifTrue: - [^self getAttributesFailed]. - (self cCode: 'FileTimeToSystemTime(&winAttrs.ftCreationTime, &sysTime)') = 0 ifTrue: - [^self timeConversionFailed]. - - self cCode: ' - tm.tm_year = sysTime.wYear - 1900; - tm.tm_mon = sysTime.wMonth - 1; - tm.tm_mday = sysTime.wDay; - - tm.tm_hour = sysTime.wHour; - tm.tm_min = sysTime.wMinute; - tm.tm_sec = sysTime.wSecond; - tm.tm_isdst = 0; - *creationDate = mktime(&tm)'. - - ^0! Item was changed: ----- Method: FileAttributesPlugin>>fileToAttributeArray:mask:array: (in category 'private - file') ----- + fileToAttributeArray: faPath mask: attributeMask array: attributeArray - fileToAttributeArray: cPathName mask: attributeMask array: attributeArray "Answer a file attribute array from pathNameOop." | getStats useLstat getAccess statArray accessArray combinedArray status fileNameOop statBuf | + <returnTypeC: #'int'> + <var: 'faPath' type: #'fapath *'> + <var: 'attributeArray' type: #'sqInt *'> + <var: 'statBuf' type: #'faStatStruct'> - <returnTypeC: 'int'> - <var: 'cPathName' type: 'char *'> - <var: 'attributeArray' type: 'sqInt *'> - <var: 'statBuf' type: 'struct stat'> "Determine which attributes to retrieve" getStats := attributeMask anyMask: 1. getAccess := attributeMask anyMask: 2. (getStats or: [getAccess]) ifFalse: ["No information has been requested, which doesn't make sense" ^self invalidArguments]. getStats ifTrue: [ useLstat := attributeMask anyMask: 4. statArray := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 12. statArray ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. status := useLstat ifFalse: + [ self faStat: faPath _: (self addressOf: statBuf ) _: (self addressOf: fileNameOop) ] - [ self putStatFor: cPathName - intoBuffer: (self addressOf: statBuf) - targetName: (self addressOf: fileNameOop) ] ifTrue: + [ self faLinkStat: faPath _: (self addressOf: statBuf ) _: (self addressOf: fileNameOop) ]. - [ self putLStatFor: cPathName - intoBuffer: (self addressOf: statBuf) - targetName: (self addressOf: fileNameOop) ]. status ~= 0 ifTrue: [^status]. + status := self statArrayFor: faPath toArray: statArray from: (self addressOf: statBuf) fileName: fileNameOop. - status := self statArrayFor: cPathName toArray: statArray from: (self addressOf: statBuf) fileName: fileNameOop. status ~= 0 ifTrue: [^status]. "Set attributeArray in case only stat() attributes have been requested" attributeArray at: 0 put: statArray ]. getAccess ifTrue: [ accessArray := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 3. accessArray ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + self faAccessAttributes: faPath _: accessArray _: 0. - self accessAttributesForFilename: cPathName into: accessArray startingAt: 0. "Set attributeArray in case only access() attributes have been requested" attributeArray at: 0 put: accessArray ]. [getStats and: [getAccess]] ifTrue: [ combinedArray := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2. combinedArray ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. attributeArray at: 0 put: combinedArray. interpreterProxy storePointer: 0 ofObject: combinedArray withValue: statArray; storePointer: 1 ofObject: combinedArray withValue: accessArray ]. ^0! Item was changed: + ----- Method: FileAttributesPlugin>>getAttributesFailed (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>getAttributesFailed (in category 'errors') ----- getAttributesFailed <inline: #always> ^-4! Item was changed: + ----- Method: FileAttributesPlugin>>invalidArguments (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>invalidArguments (in category 'errors') ----- invalidArguments <inline: #always> ^-6! Item was changed: + ----- Method: FileAttributesPlugin>>invalidRequest (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>invalidRequest (in category 'errors') ----- invalidRequest <inline: #always> ^-11! Item was removed: - ----- Method: FileAttributesPlugin>>isSymlink:boolean: (in category 'private - file') ----- - isSymlink: cPathName boolean: resultOop - "Set resultOop to a boolean indicating whether cPathName is a symbolic link. - Answer status (0 = success)" - - | status statBuf | - <var: 'cPathName' type: 'char *'> - <var: 'resultOop' type: 'sqInt *'> - <var: 'statBuf' type: 'struct stat'> - self touch: statBuf. - self cppIf: #HAVE_LSTAT == 1 ifTrue: - [status := self lst: cPathName at: (self addressOf: statBuf). - status ~= 0 ifTrue: [^self cantStatPath]. - (self S_ISLNK: statBuf st_mode) = 0 - ifFalse: [resultOop at: 0 put: interpreterProxy trueObject] - ifTrue: [resultOop at: 0 put: interpreterProxy falseObject]]. - ^0! Item was added: + ----- Method: FileAttributesPlugin>>noMoreData (in category 'errors / status') ----- + noMoreData + <inline: #always> + ^1! Item was removed: - ----- Method: FileAttributesPlugin>>offsetStatBufTimesForWIN32: (in category 'private - windows') ----- - offsetStatBufTimesForWIN32: statBufPointer - "Adjust the statBuffer to UTC, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx" - <option: #_WIN32> - <var: 'statBufPointer' type: 'struct stat *'> - | status dtzi offset | - <var: 'offset' type: 'long'> - <var: 'dtzi' type: 'TIME_ZONE_INFORMATION'> - status := self GetTimeZoneInformation: (self addressOf: dtzi). - offset := (self cCode: 'dtzi.Bias' inSmalltalk: [0]) * 60. - "Adjust for DST if required" - status = 2 ifTrue: [offset := offset - 3600]. - self cCode: 'statBufPointer->st_atime += offset'. - self cCode: 'statBufPointer->st_mtime += offset'. - self cCode: 'statBufPointer->st_ctime += offset'.! Item was removed: - ----- Method: FileAttributesPlugin>>oopFromTimeT: (in category 'private') ----- - oopFromTimeT: posixSeconds - "Answer an object representation of the provided time (time_t). - The size of time_t is platform dependent, so check the size and convert appropriately." - - <var: 'posixSeconds' type: 'time_t'> - - ^(self sizeof: #time_t) = 4 ifTrue: - [interpreterProxy signed32BitIntegerFor: posixSeconds] - ifFalse: - [interpreterProxy signed64BitIntegerFor: posixSeconds]. - ! Item was removed: - ----- Method: FileAttributesPlugin>>openDirectoryStream:ptr: (in category 'private - directory') ----- - openDirectoryStream: pathOOP ptr: osdirPtr - "Open a new directory stream. Answer a pointer to the directory stream or NULL." - - | sPtr len dir | - <var: 'osdirPtr' type: 'osdir **'> - <var: 'sPtr' declareC: 'char *sPtr'> - <var: 'dir' type: 'osdir *'> - <returnTypeC: 'int'> - sPtr := interpreterProxy arrayValueOf: pathOOP. - len := interpreterProxy sizeOfSTArrayFromCPrimitive: sPtr. - "The path buffer needs room for a trailing slash and the file name, so subtracting 2 is conservative" - len > (#PATH_MAX - 2) ifTrue: [^self stringTooLong]. - (self canOpenDirectoryStreamFor: sPtr length: len) - ifTrue: - [ - dir := self cCode: '(osdir *) malloc(sizeof(osdir))'. - dir = nil ifTrue: [^self cantAllocateMemory]. - self mem: dir path cp: sPtr y: len. - "Ensure path has a trailing slash" - self cCode: 'if (dir->path[len-1] !!= ''/'') { - dir->path[len++] = ''/''; - }'. - self cCode: 'dir->path_file = dir->path + len'. - self cCode: 'dir->path_file[0] = ''\0'''. - self cCode: 'dir->path_len = len'. - self cCode: 'dir->dp = opendir(dir->path)'. - dir dp ifNil: - [self free: dir. - ^self cantOpenDir]. - osdirPtr at: 0 put: dir. - ^0 - ]. - "If we get here, we can't open the directory" - ^self cantOpenDir - ! Item was changed: ----- Method: FileAttributesPlugin>>pathOop:toBuffer:maxLen: (in category 'private - file') ----- pathOop: pathNameOop toBuffer: cPathName maxLen: maxLen "Copy the supplied path name string object to the supplied c string buffer" | len sPtr | + <var: 'cPathName' type: #'char *'> + <var: 'sPtr' type: #'char *'> + <returnTypeC: #'int'> - <var: 'cPathName' type: 'char *'> - <var: 'sPtr' type: 'char *'> - <returnTypeC: 'int'> len := interpreterProxy stSizeOf: pathNameOop. (len >= maxLen) ifTrue: [^self stringTooLong]. "Copy pathName to the new string" sPtr := interpreterProxy arrayValueOf: pathNameOop. ((self canStatFilePath: sPtr length: len) = 0) ifTrue: [^self cantStatPath]. + self memcpy: cPathName _: sPtr _: len. - self mem: cPathName cp: sPtr y: len. cPathName at: len put: 0. ^0. ! Item was changed: ----- Method: FileAttributesPlugin>>pointerFrom: (in category 'private - directory') ----- pointerFrom: directoryPointerBytes "Answer the machine address contained in anExternalAddressOop." | ptr addressUnion idx | + <returnTypeC: #'void *'> + <var: 'ptr' type: #'unsigned char *'> - <returnTypeC: 'void *'> - <var: 'ptr' type: 'unsigned char *'> <var: 'addressUnion' type: 'union {void *address; unsigned char bytes[sizeof(void *)];}'> ((interpreterProxy is: directoryPointerBytes KindOf: 'ByteArray') and: [(interpreterProxy stSizeOf: directoryPointerBytes) = self sizeOfPointer]) ifFalse: [^ nil]. ptr := interpreterProxy arrayValueOf: directoryPointerBytes. idx := 0. [idx < self sizeOfPointer] whileTrue: [self cCode: 'addressUnion.bytes[idx] = ptr[idx]'. idx := idx + 1]. ^ self cCode: 'addressUnion.address' inSmalltalk: [addressUnion] ! Item was added: + ----- Method: FileAttributesPlugin>>posixFileTimesFrom:to: (in category 'private - posix') ----- + posixFileTimesFrom: statBufPointer to: attributeArray + "Populate attributeArray with the file times from statBufPointer" + + | attributeDate | + + <var: 'statBufPointer' type: #'faStatStruct *'> + <var: 'attributeDate' type: #'sqLong'> + + self cppIf: #_WIN32 defined ifTrue: [] ifFalse: [ + attributeDate := self faConvertUnixToLongSqueakTime: (self cCode: 'statBufPointer->st_atime'). + interpreterProxy + storePointer: 8 + ofObject: attributeArray + withValue: (interpreterProxy signed64BitIntegerFor: attributeDate). + attributeDate := self faConvertUnixToLongSqueakTime: (self cCode: 'statBufPointer->st_mtime'). + interpreterProxy + storePointer: 9 + ofObject: attributeArray + withValue: (interpreterProxy signed64BitIntegerFor: attributeDate). + attributeDate := self faConvertUnixToLongSqueakTime: (self cCode: 'statBufPointer->st_ctime'). + interpreterProxy + storePointer: 10 + ofObject: attributeArray + withValue: (interpreterProxy signed64BitIntegerFor: attributeDate); + storePointer: 11 + ofObject: attributeArray + withValue: interpreterProxy nilObject ]. + ^0! Item was added: + ----- Method: FileAttributesPlugin>>primitiveChangeMode (in category 'file primitives') ----- + primitiveChangeMode + "Set the mode of the supplied file using chmod()." + + | fileNameOop newMode status faPath | + <export: true> + <var: 'newMode' type: #'sqInt'> + <var: 'faPath' type: #'fapath *'> + + fileNameOop := interpreterProxy stackObjectValue: 1. + newMode := interpreterProxy stackIntegerValue: 0. + (interpreterProxy failed + or: [(interpreterProxy isBytes: fileNameOop) not]) ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + self cppIf: #HAVE_CHMOD ifTrue: [ + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetStPathOop: faPath _: fileNameOop. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. + + status := self chmod: (self faGetPlatPath: faPath) _: newMode. + self free: faPath. + status ~= 0 ifTrue: [ + ^interpreterProxy primitiveFailForOSError: (self cCode: 'errno')]. + ^interpreterProxy methodReturnValue: interpreterProxy nilObject. + ]. + ^interpreterProxy primitiveFailForOSError: self unsupportedOperation. + ! Item was added: + ----- Method: FileAttributesPlugin>>primitiveChangeOwner (in category 'file primitives') ----- + primitiveChangeOwner + "Set the owner of the supplied file using chown()." + + | fileNameOop ownerId groupId faPath status | + <export: true> + <var: 'faPath' type: #'fapath *'> + + fileNameOop := interpreterProxy stackObjectValue: 2. + ownerId := interpreterProxy stackIntegerValue: 1. + groupId := interpreterProxy stackIntegerValue: 0. + (interpreterProxy failed + or: [(interpreterProxy isBytes: fileNameOop) not]) ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + self cppIf: #HAVE_CHOWN ifTrue: [ + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetStPathOop: faPath _: fileNameOop. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. + + status := self chown: (self faGetPlatPath: faPath) _: ownerId _: groupId. + self free: faPath. + status ~= 0 ifTrue: [ + ^interpreterProxy primitiveFailForOSError: (self cCode: 'errno')]. + ^interpreterProxy methodReturnValue: interpreterProxy nilObject. + ]. + ^interpreterProxy primitiveFailForOSError: self unsupportedOperation. + ! Item was changed: ----- Method: FileAttributesPlugin>>primitiveClosedir (in category 'file primitives') ----- primitiveClosedir "Close the directory stream for dirPointerOop. Answer dirPointerOop on success. Raise PrimErrBadArgument if the parameter is not a ByteArray length size(void *). If closedir() returns an error raise PrimitiveOSError." + | dirPointerOop faPath result | - | dirPointerOop dirStream result | <export: true> + <var: 'fapath' type: #'faPath *'> + - <var: 'dirStream' type: 'osdir *'> dirPointerOop := interpreterProxy stackValue: 0. + faPath := self pointerFrom: dirPointerOop. + faPath ifNil: - dirStream := self pointerFrom: dirPointerOop. - dirStream ifNil: [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + result := self faCloseDirectory: faPath. - result := self closedir: dirStream dp. result = 0 ifFalse: + [^interpreterProxy primitiveFailForOSError: result]. + self free: faPath. - [^interpreterProxy primitiveFailForOSError: self unableToCloseDir]. - self free: dirStream. interpreterProxy pop: 2 thenPush: dirPointerOop! Item was changed: ----- Method: FileAttributesPlugin>>primitiveFileAttribute (in category 'file primitives') ----- primitiveFileAttribute "Answer a single file attribute. primFileAttributes: aString attributeNumber: attributeNumber aString is the path to the file attributeNumber identifies which attribute to return: 1 - 12: stat(): name, mode, ino, dev, nlink, uid, gid, size, accessDate, modifiedDate, changeDate, creationDate 13 - 15: access(): R_OK, W_OK, X_OK 16: isSymlink On error, answer a single element array containing the appropriate error code." + | fileName attributeNumber resultOop faPath | - | fileName attributeNumber resultOop fileNameOop statBuf cPathName sizeIfFile mode creationDate status | <export: true> + <var: 'faPath' type: #'fapath *'> - <var: 'statBuf' type: 'struct stat'> - <var: 'cPathName' declareC: 'char cPathName[PATH_MAX]'> - <var: 'creationDate' type: 'time_t'> fileName := interpreterProxy stackObjectValue: 1. attributeNumber := interpreterProxy stackIntegerValue: 0. (interpreterProxy failed + or: [(attributeNumber between: 1 and: 16) not + or: [(interpreterProxy isBytes: fileName) not]]) ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. - or: [(attributeNumber between: 1 and: 16) not - or: [(interpreterProxy is: fileName KindOf: 'String') not]]) ifTrue: - [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. - status := self pathOop: fileName toBuffer: cPathName maxLen: #PATH_MAX. - status ~= 0 ifTrue: - [^interpreterProxy primitiveFailForOSError: status]. - resultOop := 0. + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetStPathOop: faPath _: fileName. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. - attributeNumber < 12 ifTrue: - "Get requested stat entry" - [ - status := self - putStatFor: cPathName - intoBuffer: (self addressOf: statBuf) - targetName: (self addressOf: fileNameOop). - status ~= 0 ifTrue: - [^interpreterProxy primitiveFailForOSError: status]. - "In C, this would naturally be a switch statement, - but I don't know to mix in the smalltalk code" - attributeNumber = 1 ifTrue: [resultOop := fileNameOop]. - attributeNumber = 2 ifTrue: - [resultOop := interpreterProxy positiveMachineIntegerFor: statBuf st_mode]. - attributeNumber = 3 ifTrue: - [resultOop := interpreterProxy positive64BitIntegerFor: statBuf st_ino]. - attributeNumber = 4 ifTrue: - [resultOop := interpreterProxy positive64BitIntegerFor: statBuf st_dev]. - attributeNumber = 5 ifTrue: - [resultOop := interpreterProxy positive64BitIntegerFor: statBuf st_nlink]. - attributeNumber = 6 ifTrue: - [resultOop := interpreterProxy positiveMachineIntegerFor: statBuf st_uid]. - attributeNumber = 7 ifTrue: - [resultOop := interpreterProxy positiveMachineIntegerFor: statBuf st_gid]. - attributeNumber = 8 ifTrue: - [ - sizeIfFile := ((self S_ISDIR: statBuf st_mode) = 0) - ifTrue: [statBuf st_size] - ifFalse: [0]. - resultOop := interpreterProxy positiveMachineIntegerFor: sizeIfFile - ]. - attributeNumber = 9 ifTrue: - [resultOop := self oopFromTimeT: statBuf st_atime]. - attributeNumber = 10 ifTrue: - [resultOop := self oopFromTimeT: statBuf st_mtime]. - attributeNumber = 11 ifTrue: - [resultOop := self oopFromTimeT: statBuf st_ctime]. - ] - ifFalse: [attributeNumber = 12 ifTrue: - [ - self cppIf: #_WIN32 defined ifTrue: [ - status := self fileCreationTimeFor: cPathName - length: cPathName strlen - to: (self addressOf: creationDate put: [:val| creationDate := val]). - status ~= 0 ifTrue: - [^interpreterProxy primitiveFailForOSError: status]. - resultOop := self oopFromTimeT: creationDate ] - ifFalse: [ - resultOop := interpreterProxy nilObject ] - ] - ifFalse: [attributeNumber < 16 ifTrue: - "Get requested access entry" - [ - attributeNumber = 13 ifTrue: [mode := self fileReadableFlag]. - attributeNumber = 14 ifTrue: [mode := self fileWriteableFlag]. - attributeNumber = 15 ifTrue: [mode := self fileExecutableFlag]. - resultOop := ((self acc: cPathName ess: mode) = 0) - ifTrue: [interpreterProxy trueObject] - ifFalse: [interpreterProxy falseObject]. - ] - ifFalse: "attributeNumber = 16" - [ - status := self isSymlink: cPathName boolean: (self addressOf: resultOop put: [:val| resultOop := val]). - status ~= 0 ifTrue: - [^interpreterProxy primitiveFailForOSError: status]. - ]]]. + resultOop := self faFileAttribute: faPath _: attributeNumber. + self free: faPath. + interpreterProxy failed ifTrue: [ + ^interpreterProxy primitiveFailureCode]. + resultOop = 0 ifTrue: ["It shouldn't be possible to get here" + interpreterProxy primitiveFailForOSError: self unexpectedError] + ifFalse: [interpreterProxy methodReturnValue: resultOop]! - interpreterProxy primitiveFail] - ifFalse: [interpreterProxy pop: 3 thenPush: resultOop]! Item was changed: ----- Method: FileAttributesPlugin>>primitiveFileAttributes (in category 'file primitives') ----- primitiveFileAttributes "Answer an array of file attributes. primFileAttributes: aString mask: attributeMask aString is the path to the file attributeMask indicates which attributes to retrieve: bit 0 - get stat() attributes bit 1 - get access() attributes bit 2 - use lstat() instead of stat() On error answer the appropriate error code (Integer)" + | fileName attributeMask attributeArray faPath status | - | fileName attributeMask attributeArray cPathName status | <export: true> + <var: 'faPath' type: #'fapath *'> + - <var: 'cPathName' declareC: 'char cPathName[PATH_MAX]'> fileName := interpreterProxy stackObjectValue: 1. attributeMask := interpreterProxy stackIntegerValue: 0. (interpreterProxy failed + or: [(interpreterProxy isBytes: fileName) not]) ifTrue: - or: [(interpreterProxy is: fileName KindOf: 'String') not]) ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. - status := self pathOop: fileName toBuffer: cPathName maxLen: #PATH_MAX. - status ~= 0 ifTrue: - [^interpreterProxy primitiveFailForOSError: status]. + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSet: faPath StPathOop: fileName. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. + + status := self fileToAttributeArray: faPath - status := self fileToAttributeArray: cPathName mask: attributeMask array: (self addressOf: attributeArray put: [:val| attributeArray := val]). + self free: faPath. status ~= 0 ifTrue: [interpreterProxy primitiveFailForOSError: status] + ifFalse: [interpreterProxy methodReturnValue: attributeArray]! - ifFalse: [interpreterProxy pop: 3 thenPush: attributeArray]! Item was changed: ----- Method: FileAttributesPlugin>>primitiveFileExists (in category 'file primitives') ----- primitiveFileExists "Check for existence of a file with a call to access()." + | fileNameOop faPath resultOop | - | pathString status accessFlag | <export: true> + <var: 'faPath'type: #'fapath *'> + + fileNameOop := interpreterProxy stackObjectValue: 0. + (interpreterProxy isBytes: fileNameOop) ifFalse: - <var: 'accessFlag' type: 'sqInt'> - pathString := interpreterProxy stackObjectValue: 0. - (interpreterProxy is: pathString KindOf: 'String') ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetStPathOop: faPath _: fileNameOop. + interpreterProxy failed ifTrue: [^interpreterProxy primitiveFailureCode]. + + resultOop := self faExists: faPath. + self free: faPath. + ^interpreterProxy methodReturnValue: resultOop. + ! - status := self checkAccess: pathString mode: self fileOKFlag to: (self addressOf: accessFlag). - status = 0 ifFalse: [^interpreterProxy primitiveFailForOSError: status]. - interpreterProxy pop: 2 thenPush: (accessFlag = 0 - ifTrue: [interpreterProxy trueObject] - ifFalse: [interpreterProxy falseObject])! Item was changed: ----- Method: FileAttributesPlugin>>primitiveLogicalDrives (in category 'file primitives') ----- primitiveLogicalDrives "Answer the logical drive mask on windows" + | mask | <export: true> <var: 'mask' type: #'unsigned int'> self cppIf: #_WIN32 defined ifTrue: + [ - [| mask | mask := self GetLogicalDrives. mask ~= 0 ifTrue: [^interpreterProxy pop: 1 thenPush: (interpreterProxy positive32BitIntegerFor: mask)]]. interpreterProxy primitiveFail! Item was changed: ----- Method: FileAttributesPlugin>>primitiveOpendir (in category 'file primitives') ----- primitiveOpendir "self primOpendir: '/etc'" + | dirName faPath dirOop status resultOop | - | dirName dir dirOop status | <export: true> + <var: 'faPath' type: #'fapath *'> + - <var: 'dir' type: 'osdir *'> dirName := interpreterProxy stackObjectValue: 0. + (interpreterProxy isBytes: dirName) ifFalse: - (interpreterProxy is: dirName KindOf: 'String') ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSet: faPath StDirOop: dirName. + + (self canOpenDirectoryStreamFor: (self faGetStPath: faPath) length: (self faGetStPathLen: faPath)) ifFalse: [ + self free: faPath. + ^interpreterProxy primitiveFailForOSError: self cantOpenDir]. + + status := self faOpenDirectory: faPath. + status = self noMoreData ifTrue: [ + self free: faPath. + ^interpreterProxy pop: 2 thenPush: interpreterProxy nilObject]. + status < 0 ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailForOSError: status]. + resultOop := self processDirectory: faPath. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode ]. + + self remapOop: resultOop in: + [ dirOop := self addressObjectFor: faPath ]. + ^interpreterProxy + storePointer: 2 ofObject: resultOop withValue: dirOop; + methodReturnValue: resultOop.! - status := self openDirectoryStream: dirName ptr: (self addressOf: dir). - status ~= 0 ifTrue: [^interpreterProxy primitiveFailForOSError: status]. - dirOop := self addressObjectFor: dir. - interpreterProxy pop: 2 thenPush: dirOop! Item was changed: ----- Method: FileAttributesPlugin>>primitivePathMax (in category 'file primitives') ----- primitivePathMax "Answer the value of PATH_MAX for the current VM" <export: true> + ^interpreterProxy pop: 1 thenPush: (interpreterProxy integerObjectOf: #FA_PATH_MAX)! - ^interpreterProxy pop: 1 thenPush: (interpreterProxy integerObjectOf: #PATH_MAX)! Item was added: + ----- Method: FileAttributesPlugin>>primitivePlatToStPath (in category 'file primitives') ----- + primitivePlatToStPath + "Convert the supplied file name (platform encoded) to the St UTF8 encoded byte array" + + | fileName faPath resultOop byteArrayPtr | + <export: true> + <var: 'faPath' type: #'fapath *'> + <var: 'byteArrayPtr' type: #'unsigned char *'> + + fileName := interpreterProxy stackObjectValue: 0. + (interpreterProxy failed + or: [(interpreterProxy isBytes: fileName) not]) ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetPlatPathOop: faPath _: fileName. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. + + resultOop := interpreterProxy + instantiateClass: interpreterProxy classByteArray + indexableSize: (self faGetStPathLen: faPath). + resultOop ifNil: [ + self free: faPath. + ^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + byteArrayPtr := interpreterProxy arrayValueOf: resultOop. + self memcpy: byteArrayPtr _: (self faGetStPath: faPath) _: (self faGetStPathLen: faPath). + self free: faPath. + + ^interpreterProxy methodReturnValue: resultOop. + ! Item was changed: ----- Method: FileAttributesPlugin>>primitiveReaddir (in category 'file primitives') ----- primitiveReaddir "Get the next entry in the directory stream. Answer the name of the entry, or + nil for the end of the directory stream. + Arguments: + - directoryPointer (ByteArray)" - nil for the end of the directory stream." + | dirPointerOop faPath resultArray status | - | dirPointerOop dirStream ent entryName attributeArray resultArray haveEntry entry_len status | <export: true> + <var: 'faPath' type: #'fapath *'> - <var: 'ent' type: 'struct dirent *'> - <var: 'dirStream' type: 'osdir *'> - <var: 'haveEntry' type: #int> dirPointerOop := interpreterProxy stackValue: 0. + faPath := self pointerFrom: dirPointerOop. + faPath ifNil: - dirStream := self pointerFrom: dirPointerOop. - dirStream ifNil: [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + status := self faReadDirectory: faPath. + status = self noMoreData ifTrue: - haveEntry := 0. - [ent := self readdir: dirStream dp. - self cCode: 'if (ent == NULL || - ((!! (ent->d_name[0] == ''.'' && strlen(ent->d_name) == 1)) && strcmp(ent->d_name, ".."))) - haveEntry = 1'. - haveEntry = 0] whileTrue. - ent ifNil: "This is the normal case for the end of a directory stream, - although it may indicate other error conditions for which errno would be updated. - Assume the normal case here." [^interpreterProxy pop: 2 thenPush: interpreterProxy nilObject]. + status < 0 ifTrue: - status := self byteArrayFromCString: ent d_name to: (self addressOf: entryName put: [:val| entryName := val]). - status ~= 0 ifTrue: [^interpreterProxy primitiveFailForOSError: status]. + resultArray := self processDirectory: faPath. + interpreterProxy failed ifTrue: [^interpreterProxy primitiveFailureCode]. - "Build the path name (append the entry name to the path name)" - entry_len := self strlen: ent d_name. - [dirStream path_len + entry_len > (#PATH_MAX - 1)] ifTrue: - [^interpreterProxy primitiveFailForOSError: self stringTooLong]. - self mem: dirStream path_file cp: ent d_name y: entry_len. - dirStream path_file at: entry_len put: 0. - - status := self fileToAttributeArray: dirStream path mask: 1 array: (self addressOf: attributeArray put: [:val| attributeArray := val]). - "If the stat() fails, still return the filename, just no attributes" - status ~= 0 ifTrue: [attributeArray := interpreterProxy nilObject]. - - self remapOop: #(entryName attributeArray) - in: [resultArray := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2]. - resultArray ifNil: - [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. interpreterProxy - storePointer: 0 ofObject: resultArray withValue: entryName; - storePointer: 1 ofObject: resultArray withValue: attributeArray; pop: 2 thenPush: resultArray! Item was changed: ----- Method: FileAttributesPlugin>>primitiveRewinddir (in category 'file primitives') ----- primitiveRewinddir "Set directoryStream to first entry. Answer dirPointerOop." + | dirPointerOop faPath status resultOop | - | dirPointerOop dirStream | <export: true> + <var: 'faPath' type: #'fapath *'> - <var: 'dirStream' declareC: 'osdir *dirStream'> dirPointerOop := interpreterProxy stackValue: 0. + faPath := self pointerFrom: dirPointerOop. + faPath ifNil: - dirStream := self pointerFrom: dirPointerOop. - dirStream ifNil: [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + status := self faRewindDirectory: faPath. + status < 0 ifTrue: [^interpreterProxy primitiveFailForOSError: status]. + resultOop := self processDirectory: faPath. + interpreterProxy failed ifTrue: [^interpreterProxy primitiveFailureCode ]. + ^interpreterProxy methodReturnValue: resultOop.! - self rewinddir: dirStream dp. - interpreterProxy pop: 2 thenPush: dirPointerOop! Item was added: + ----- Method: FileAttributesPlugin>>primitiveStToPlatPath (in category 'file primitives') ----- + primitiveStToPlatPath + "Convert the supplied file name (UTF8 encoded) to the platform encoded byte array" + + | fileName faPath resultOop byteArrayPtr | + <export: true> + <var: 'faPath' type: #'fapath *'> + <var: 'byteArrayPtr' type: #'unsigned char *'> + + fileName := interpreterProxy stackObjectValue: 0. + (interpreterProxy failed + or: [(interpreterProxy isBytes: fileName) not]) ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetStPathOop: faPath _: fileName. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. + + resultOop := interpreterProxy + instantiateClass: interpreterProxy classByteArray + indexableSize: (self faGetPlatPathByteCount: faPath). + resultOop ifNil: [ + self free: faPath. + ^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + byteArrayPtr := interpreterProxy arrayValueOf: resultOop. + self memcpy: byteArrayPtr _: (self faGetPlatPath: faPath) _: (self faGetPlatPathByteCount: faPath). + self free: faPath. + + ^interpreterProxy methodReturnValue: resultOop. + ! Item was added: + ----- Method: FileAttributesPlugin>>primitiveSymlinkChangeOwner (in category 'file primitives') ----- + primitiveSymlinkChangeOwner + "Set the owner of the supplied file using chown()." + + | fileNameOop ownerId groupId faPath status | + <export: true> + <var: 'faPath' type: #'fapath *'> + + fileNameOop := interpreterProxy stackObjectValue: 2. + ownerId := interpreterProxy stackIntegerValue: 1. + groupId := interpreterProxy stackIntegerValue: 0. + (interpreterProxy failed + or: [(interpreterProxy isBytes: fileNameOop) not]) ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadArgument]. + self cppIf: #HAVE_CHOWN ifTrue: [ + faPath := self cCode: '(fapath *) calloc(1, sizeof(fapath))'. + faPath = nil ifTrue: [^interpreterProxy primitiveFailForOSError: self cantAllocateMemory]. + self faSetStPathOop: faPath _: fileNameOop. + interpreterProxy failed ifTrue: [ + self free: faPath. + ^interpreterProxy primitiveFailureCode]. + + status := self lchown: (self faGetPlatPath: faPath) _: ownerId _: groupId. + self free: faPath. + status ~= 0 ifTrue: + [^interpreterProxy primitiveFailForOSError: (self cCode: 'errno')]. + ^interpreterProxy methodReturnValue: interpreterProxy nilObject. + ]. + ^interpreterProxy primitiveFailForOSError: self unsupportedOperation. + ! Item was added: + ----- Method: FileAttributesPlugin>>processDirectory: (in category 'private') ----- + processDirectory: faPath + "The supplied faPath contains the full path to the current entry while iterating over a directory. + Convert the file name to an object, get the attributes and answer the resulting array." + + | status entryName attributeArray resultArray | + <var: 'faPath' type: #'fapath *'> + + status := self faChar: (self faGetStFile: faPath) + ToByteArray: (self addressOf: entryName put: [:val | entryName := val]). + status ~= 0 ifTrue: + [ ^interpreterProxy primitiveFailForOSError: status]. + + status := self fileToAttributeArray: faPath mask: 1 array: (self addressOf: attributeArray put: [:val| attributeArray := val]). + "If the stat() fails, still return the filename, just no attributes" + status ~= 0 ifTrue: [attributeArray := interpreterProxy nilObject]. + + "resultArray: entryName, attributeArray, dirPtrOop" + self remapOop: #(entryName attributeArray) + in: [resultArray := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 3]. + resultArray ifNil: + [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + interpreterProxy + storePointer: 0 ofObject: resultArray withValue: entryName; + storePointer: 1 ofObject: resultArray withValue: attributeArray. + ^resultArray! Item was removed: - ----- Method: FileAttributesPlugin>>putLStatFor:intoBuffer:targetName: (in category 'private - file') ----- - putLStatFor: cPathName intoBuffer: statBufPointer targetName: fileNameOop - "Call stat() on cPathName, storing the results in - the buffer at statBufPointer." - - | cLinkName len status | - <returnTypeC: 'sqInt'> - <var: 'cPathName' type: 'char *'> - <var: 'statBufPointer' type: 'struct stat *'> - <var: 'cLinkName' declareC: 'char cLinkName[PATH_MAX]'> - <var: 'fileNameOop' type: 'sqInt *'> - - self cppIf: #HAVE_LSTAT = 1 ifTrue: [ - status := self lst: cPathName at: statBufPointer. - status ~= 0 ifTrue: [^self cantStatPath]. - (self S_ISLNK: statBufPointer st_mode) = 0 - ifFalse: [ - len := self readLink: cPathName into: cLinkName maxLength: #PATH_MAX. - len < 0 ifTrue: [^len]. - status := self byteArrayFromCString: cLinkName to: fileNameOop] - ifTrue: - [fileNameOop at: 0 put: interpreterProxy nilObject]. - ] ifFalse: [ "#HAVE_LSTAT = 1" - status := self invalidRequest. - ]. - ^status - ! Item was removed: - ----- Method: FileAttributesPlugin>>putStatFor:intoBuffer:targetName: (in category 'private - file') ----- - putStatFor: cPathName intoBuffer: statBufPointer targetName: fileNameOop - "Call stat() on cPathName, storing the results in - the buffer at statBufPointer." - - | status | - <var: 'cPathName' type: 'char *'> - <var: 'statBufPointer' type: 'struct stat *'> - <var: 'fileNameOop' type: 'sqInt *'> - - status := self st: cPathName at: statBufPointer. - status ~= 0 ifTrue: [^self cantStatPath]. - self cppIf: #_WIN32 defined - ifTrue: [self offsetStatBufTimesForWIN32: statBufPointer]. - fileNameOop at: 0 put: interpreterProxy nilObject. - ^0! Item was changed: ----- Method: FileAttributesPlugin>>readLink:into:maxLength: (in category 'private - file') ----- readLink: cPathName into: cLinkPtr maxLength: maxLength "Get the target filename of the supplied symbolic link." | len | + <var: 'cPathName' type: #'char *'> + <var: 'cLinkPtr' type: #'char *'> + <var: 'maxLength' type: #'size_t'> - <var: 'cPathName' type: 'char *'> - <var: 'cLinkPtr' type: 'char *'> - <var: 'maxLength' type: 'size_t'> <var: 'len' type: #sqInt> "len must be signed so that -1 can be communicated as an error." len := self cppIf: #_WIN32 defined ifTrue: [-1] ifFalse: [self read: cPathName li: cLinkPtr nk: maxLength]. len < 0 ifTrue: [self cppIf: #'INDEBUG' defined ifTrue: [self cCode: 'fprintf(stderr, "FileAttributesPlugin: unable to readlink(): %d, errno=%d\n", len, errno)']. ^self cantReadlink]. cLinkPtr at: len put: 0. ^len! Item was changed: ----- Method: FileAttributesPlugin>>statArrayFor:toArray:from:fileName: (in category 'private - file') ----- + statArrayFor: faPath toArray: attributeArray from: statBufPointer fileName: fileNameOop - statArrayFor: cPathName toArray: attributeArray from: statBufPointer fileName: fileNameOop "Answer a file entry array from the supplied statBufPointer" + | sizeIfFile status | + <var: 'faPath' type: #'fapath *'> + <var: 'statBufPointer' type: #'faStatStruct *'> - | sizeIfFile creationDate status | - <var: 'cPathName' type: 'char *'> - <var: 'statBufPointer' type: 'struct stat *'> - <var: 'creationDate' type: 'time_t'> + sizeIfFile := (self cCode: 'S_ISDIR(statBufPointer->st_mode)') = 0 + ifTrue: [self cCode: 'statBufPointer->st_size'] - sizeIfFile := (self S_ISDIR: statBufPointer st_mode) = 0 - ifTrue: [statBufPointer st_size] ifFalse: [0]. interpreterProxy storePointer: 0 ofObject: attributeArray withValue: fileNameOop; storePointer: 1 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: (self cCode: 'statBufPointer->st_mode')); - withValue: (interpreterProxy positiveMachineIntegerFor: statBufPointer st_mode); storePointer: 2 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: (self cCode: 'statBufPointer->st_ino')); - withValue: (interpreterProxy positive64BitIntegerFor: statBufPointer st_ino); storePointer: 3 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: (self cCode: 'statBufPointer->st_dev')); - withValue: (interpreterProxy positive64BitIntegerFor: statBufPointer st_dev); storePointer: 4 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: (self cCode: 'statBufPointer->st_nlink')); - withValue: (interpreterProxy positive64BitIntegerFor: statBufPointer st_nlink); storePointer: 5 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: (self cCode: 'statBufPointer->st_uid')); - withValue: (interpreterProxy positiveMachineIntegerFor: statBufPointer st_uid); storePointer: 6 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: (self cCode: 'statBufPointer->st_gid')); - withValue: (interpreterProxy positiveMachineIntegerFor: statBufPointer st_gid); storePointer: 7 ofObject: attributeArray + withValue: (interpreterProxy positive64BitIntegerFor: sizeIfFile). + - withValue: (interpreterProxy positive64BitIntegerFor: sizeIfFile); - storePointer: 8 - ofObject: attributeArray - withValue: (self oopFromTimeT: statBufPointer st_atime); - storePointer: 9 - ofObject: attributeArray - withValue: (self oopFromTimeT: statBufPointer st_mtime); - storePointer: 10 - ofObject: attributeArray - withValue: (self oopFromTimeT: statBufPointer st_ctime). self cppIf: #_WIN32 defined + ifTrue: [ status := self winFileTimesFor: faPath to: attributeArray ] + ifFalse: [ status := self posixFileTimesFrom: statBufPointer to: attributeArray ]. + + ^status + ! - ifTrue: - [status := self fileCreationTimeFor: cPathName - length: cPathName strlen - to: (self addressOf: creationDate put: [:val| creationDate := val]). - interpreterProxy - storePointer: 11 - ofObject: attributeArray - withValue: (status = 0 - ifTrue: [self oopFromTimeT: creationDate] - ifFalse: [interpreterProxy nilObject])] - ifFalse: - [interpreterProxy - storePointer: 11 - ofObject: attributeArray - withValue: interpreterProxy nilObject]. - ^0! Item was changed: + ----- Method: FileAttributesPlugin>>statFailed (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>statFailed (in category 'errors') ----- statFailed "A call to stat() failed" <inline: #always> ^-2! Item was changed: ----- Method: FileAttributesPlugin>>stringFromCString: (in category 'private') ----- stringFromCString: aCString "Answer a new String copied from a null-terminated C string. Caution: This may invoke the garbage collector." | len newString | + <var: 'aCString' type: #'const char *'> - <var: 'aCString' type: 'const char *'> len := self strlen: aCString. newString := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: len. newString ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + self strncpy: (interpreterProxy arrayValueOf: newString) + _: aCString + _: len. "(char *)strncpy()" - self st: (interpreterProxy arrayValueOf: newString) - rn: aCString - cpy: len. "(char *)strncpy()" ^ newString ! Item was changed: + ----- Method: FileAttributesPlugin>>stringTooLong (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>stringTooLong (in category 'errors') ----- stringTooLong "String too long. A file path name was longer than PATH_MAX" <inline: #always> ^-1! Item was changed: + ----- Method: FileAttributesPlugin>>timeConversionFailed (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>timeConversionFailed (in category 'errors') ----- timeConversionFailed <inline: #always> ^-5! Item was changed: + ----- Method: FileAttributesPlugin>>unableToCloseDir (in category 'errors / status') ----- - ----- Method: FileAttributesPlugin>>unableToCloseDir (in category 'errors') ----- unableToCloseDir "The call to closedir() failed" <inline: #always> ^-12! Item was added: + ----- Method: FileAttributesPlugin>>unexpectedError (in category 'errors / status') ----- + unexpectedError + "This is normally used where a catch-all is placed, but not expected to be used" + <inline: #always> + ^-14! Item was added: + ----- Method: FileAttributesPlugin>>unsupportedOperation (in category 'errors / status') ----- + unsupportedOperation + "The requested operation is not supported on the current platform" + <inline: #always> + ^-13! Item was changed: ----- Method: FileAttributesPlugin>>versionString (in category 'version string') ----- versionString "Answer a string containing the version string for this plugin." <inline: #always> + ^'2.0.2'! - ^'1.2.6'! Item was added: + ----- Method: FileAttributesPlugin>>winFileCreationTimeFor:to: (in category 'private - windows') ----- + winFileCreationTimeFor: winAttrs to: creationDate + "Set the file creation time from the supplied attributes." + <option: #_WIN32> + + | sysTime fileTime | + + <var: 'winAttrs' type: #'WIN32_FILE_ATTRIBUTE_DATA *'> + <var: 'creationDate' type: #'sqLong *'> + <var: 'fileTime' type: #'FILETIME'> + <var: 'sysTime' type: #'SYSTEMTIME'> + + self touch: sysTime. + self touch: fileTime. + + (self cCode: 'FileTimeToLocalFileTime(&winAttrs->ftCreationTime, &fileTime)') = 0 ifTrue: + [^self timeConversionFailed]. + (self cCode: 'FileTimeToSystemTime(&fileTime, &sysTime)') = 0 ifTrue: + [^self timeConversionFailed]. + self cCode: '*creationDate = convertWinToSqueakTime(sysTime)'. + + ^0! Item was added: + ----- Method: FileAttributesPlugin>>winFileLastAccessTimeFor:to: (in category 'private - windows') ----- + winFileLastAccessTimeFor: winAttrs to: accessDate + "Set the file creation time from the supplied attributes." + <option: #_WIN32> + + | sysTime fileTime | + + <var: 'winAttrs' type: #'WIN32_FILE_ATTRIBUTE_DATA *'> + <var: 'accessDate' type: #'sqLong *'> + <var: 'fileTime' type: #'FILETIME'> + <var: 'sysTime' type: #'SYSTEMTIME'> + + self touch: sysTime. + self touch: fileTime. + + (self cCode: 'FileTimeToLocalFileTime(&winAttrs->ftLastAccessTime, &fileTime)') = 0 ifTrue: + [^self timeConversionFailed]. + (self cCode: 'FileTimeToSystemTime(&fileTime, &sysTime)') = 0 ifTrue: + [^self timeConversionFailed]. + self cCode: '*accessDate = convertWinToSqueakTime(sysTime)'. + + ^0! Item was added: + ----- Method: FileAttributesPlugin>>winFileLastWriteTimeFor:to: (in category 'private - windows') ----- + winFileLastWriteTimeFor: winAttrs to: writeDate + "Set the file write time from the supplied attributes." + <option: #_WIN32> + + | sysTime fileTime | + + <var: 'winAttrs' type: #'WIN32_FILE_ATTRIBUTE_DATA *'> + <var: 'writeDate' type: #'sqLong *'> + <var: 'fileTime' type: #'FILETIME'> + <var: 'sysTime' type: #'SYSTEMTIME'> + + self touch: sysTime. + self touch: fileTime. + + (self cCode: 'FileTimeToLocalFileTime(&winAttrs->ftLastWriteTime, &fileTime)') = 0 ifTrue: + [^self timeConversionFailed]. + (self cCode: 'FileTimeToSystemTime(&fileTime, &sysTime)') = 0 ifTrue: + [^self timeConversionFailed]. + self cCode: '*writeDate = convertWinToSqueakTime(sysTime)'. + + ^0! Item was added: + ----- Method: FileAttributesPlugin>>winFileTimesFor:to: (in category 'private - windows') ----- + winFileTimesFor: faPath to: attributeArray + <inline: #never> + <option: #_WIN32> + + | winAttrs attributeDate status | + <var: 'faPath' type: #'fapath *'> + <var: 'attributeDate' type: #'sqLong'> + <var: 'winAttrs' type: #'WIN32_FILE_ATTRIBUTE_DATA'> + + "Get the file attributes" + status := self cCode: 'GetFileAttributesExW(faGetPlatPath(faPath), GetFileExInfoStandard, &winAttrs)'. + status = 0 ifTrue: [^self getAttributesFailed]. + + "Set the accessDate" + status := self winFileLastAccessTimeFor: (self addressOf: winAttrs) to: (self addressOf: attributeDate). + status = 0 ifFalse: [^status]. + interpreterProxy + storePointer: 8 + ofObject: attributeArray + withValue: (interpreterProxy signed64BitIntegerFor: attributeDate). + + "Set the modifiedDate" + status := self winFileLastWriteTimeFor: (self addressOf: winAttrs) to: (self addressOf: attributeDate). + status = 0 ifFalse: [^status]. + interpreterProxy + storePointer: 9 + ofObject: attributeArray + withValue: (interpreterProxy signed64BitIntegerFor: attributeDate). + + "Set the changeDate" + interpreterProxy + storePointer: 10 + ofObject: attributeArray + withValue: interpreterProxy nilObject. + + "Set the creationDate" + status := self winFileCreationTimeFor: (self addressOf: winAttrs) to: (self addressOf: attributeDate). + status = 0 ifFalse: [^status]. + interpreterProxy + storePointer: 11 + ofObject: attributeArray + withValue: (interpreterProxy signed64BitIntegerFor: attributeDate). + + ^0 + ! |
Free forum by Nabble | Edit this page |