UnixOperatingSystem.st
changeset 14568 ca342ae94cb7
parent 14564 2f373e43fd1a
child 14575 c696ca8d05bd
equal deleted inserted replaced
14567:757c038e8a90 14568:ca342ae94cb7
  3408     "create a new directory with name 'aPathName', which may be an absolute
  3408     "create a new directory with name 'aPathName', which may be an absolute
  3409      path, or relative to the current directory.
  3409      path, or relative to the current directory.
  3410      Return true if successful (or the directory existed already), false if failed.
  3410      Return true if successful (or the directory existed already), false if failed.
  3411      This is a low-level entry - use Filename protocol for compatibility."
  3411      This is a low-level entry - use Filename protocol for compatibility."
  3412 
  3412 
       
  3413     |encodedPathName|
       
  3414 
       
  3415     encodedPathName := self encodePath:aPathName.
       
  3416 
  3413 %{
  3417 %{
  3414     if (__isStringLike(aPathName) && __isSmallInteger(umask)) {
  3418     if (__isStringLike(encodedPathName) && __isSmallInteger(umask)) {
  3415 	if (mkdir(__stringVal(aPathName), __smallIntegerVal(umask)) >= 0) {
  3419         if (mkdir(__stringVal(encodedPathName), __smallIntegerVal(umask)) >= 0) {
  3416 	    RETURN(true);
  3420             RETURN(true);
  3417 	}
  3421         }
  3418 	@global(LastErrorNumber) = __mkSmallInteger(errno);
  3422         @global(LastErrorNumber) = __mkSmallInteger(errno);
  3419     }
  3423     }
  3420 %}.
  3424 %}.
  3421     "/ could not create - if it already existed this is ok
  3425     "/ could not create - if it already existed this is ok
  3422 
  3426 
  3423     (self isDirectory:aPathName) ifTrue:[^ true].
  3427     (self isDirectory:aPathName) ifTrue:[^ true].
  3446 
  3450 
  3447 createHardLinkFrom:oldPath to:newPath
  3451 createHardLinkFrom:oldPath to:newPath
  3448     "link the file 'oldPath' to 'newPath'. The link will be a hard link.
  3452     "link the file 'oldPath' to 'newPath'. The link will be a hard link.
  3449      Return true if successful, false if not."
  3453      Return true if successful, false if not."
  3450 
  3454 
       
  3455     |encodedOldPathName encodedNewPathName|
       
  3456 
       
  3457     encodedOldPathName := self encodePath:oldPath.
       
  3458     encodedNewPathName := self encodePath:newPath.
       
  3459 
  3451 %{
  3460 %{
  3452     int ret;
  3461     int ret;
  3453 
  3462 
  3454     if (__isStringLike(oldPath) && __isStringLike(newPath)) {
  3463     if (__isStringLike(encodedOldPathName) && __isStringLike(encodedNewPathName)) {
  3455 	__BEGIN_INTERRUPTABLE__
  3464         __BEGIN_INTERRUPTABLE__
  3456 	do {
  3465         do {
  3457 	    ret = link((char *) __stringVal(oldPath), (char *) __stringVal(newPath));
  3466             ret = link((char *) __stringVal(encodedOldPathName), (char *) __stringVal(encodedNewPathName));
  3458 	} while (ret < 0 && errno == EINTR);
  3467         } while (ret < 0 && errno == EINTR);
  3459 	__END_INTERRUPTABLE__
  3468         __END_INTERRUPTABLE__
  3460 	if (ret < 0) {
  3469         if (ret < 0) {
  3461 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3470             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3462 	    RETURN ( false );
  3471             RETURN ( false );
  3463 	}
  3472         }
  3464 	RETURN (true);
  3473         RETURN (true);
  3465     }
  3474     }
  3466 %}.
  3475 %}.
  3467     "/
  3476     "/
  3468     "/ bad argument(s) given
  3477     "/ bad argument(s) given
  3469     "/
  3478     "/
  3477 createSymbolicLinkFrom:oldPath to:newPath
  3486 createSymbolicLinkFrom:oldPath to:newPath
  3478     "make a symbolic link for 'newPath' to the file 'oldPath'.
  3487     "make a symbolic link for 'newPath' to the file 'oldPath'.
  3479      The link will be a soft (symbolic) link.
  3488      The link will be a soft (symbolic) link.
  3480      Return true if successful, false if not."
  3489      Return true if successful, false if not."
  3481 
  3490 
       
  3491     |encodedOldPathName encodedNewPathName|
       
  3492 
       
  3493     encodedOldPathName := self encodePath:oldPath.
       
  3494     encodedNewPathName := self encodePath:newPath.
  3482 %{
  3495 %{
  3483 #ifdef S_IFLNK
  3496 #ifdef S_IFLNK
  3484     int ret;
  3497     int ret;
  3485 
  3498 
  3486     if (__isStringLike(oldPath) && __isStringLike(newPath)) {
  3499     if (__isStringLike(encodedOldPathName) && __isStringLike(encodedNewPathName)) {
  3487 	__BEGIN_INTERRUPTABLE__
  3500         __BEGIN_INTERRUPTABLE__
  3488 	do {
  3501         do {
  3489 	    ret = symlink((char *) __stringVal(oldPath), (char *) __stringVal(newPath));
  3502             ret = symlink((char *) __stringVal(encodedOldPathName), (char *) __stringVal(encodedNewPathName));
  3490 	} while (ret < 0 && errno == EINTR);
  3503         } while (ret < 0 && errno == EINTR);
  3491 	__END_INTERRUPTABLE__
  3504         __END_INTERRUPTABLE__
  3492 	if (ret < 0) {
  3505         if (ret < 0) {
  3493 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3506             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3494 	    RETURN ( false );
  3507             RETURN ( false );
  3495 	}
  3508         }
  3496 	RETURN (true);
  3509         RETURN (true);
  3497     }
  3510     }
  3498 #endif
  3511 #endif
  3499 %}.
  3512 %}.
  3500     (oldPath isString not or:[newPath isString not]) ifTrue:[
  3513     (encodedOldPathName isString not or:[encodedNewPathName isString not]) ifTrue:[
  3501 	"/
  3514         "/
  3502 	"/ bad argument(s) given
  3515         "/ bad argument(s) given
  3503 	"/
  3516         "/
  3504 	^ self primitiveFailed
  3517         ^ self primitiveFailed
  3505     ].
  3518     ].
  3506 
  3519 
  3507     "/
  3520     "/
  3508     "/ this Unix does not seem to support symbolic links
  3521     "/ this Unix does not seem to support symbolic links
  3509     "/
  3522     "/
  3516 
  3529 
  3517 open:path attributes:attributes mode:modeInteger
  3530 open:path attributes:attributes mode:modeInteger
  3518     "open a file, return an os specific fileHandle.
  3531     "open a file, return an os specific fileHandle.
  3519      openmode is a symbol defining the way to open
  3532      openmode is a symbol defining the way to open
  3520      valid modes are:
  3533      valid modes are:
  3521 	#O_RDONLY
  3534         #O_RDONLY
  3522 	#O_RDWR
  3535         #O_RDWR
  3523 	#O_WRONLY
  3536         #O_WRONLY
  3524 	#O_CREAT
  3537         #O_CREAT
  3525 	#O_APPEND
  3538         #O_APPEND
  3526 	#O_SYNC
  3539         #O_SYNC
  3527 	#O_LARGEFILE
  3540         #O_LARGEFILE
  3528 
  3541 
  3529      This is a private entry, but maybe useful to open/create a file in a special mode,
  3542      This is a private entry, but maybe useful to open/create a file in a special mode,
  3530      which is proprietrary to the operatingSystem."
  3543      which is proprietrary to the operatingSystem."
  3531 
  3544 
  3532     |error fileDescriptor|
  3545     |error fileDescriptor encodedPathName|
       
  3546 
       
  3547     encodedPathName := self encodePath:path.
  3533 
  3548 
  3534 %{
  3549 %{
  3535     OBJ *ap;
  3550     OBJ *ap;
  3536     int nAttributes;
  3551     int nAttributes;
  3537     int fd;
  3552     int fd;
  3538     int mode, openFlags = 0;
  3553     int mode, openFlags = 0;
  3539     int n;
  3554     int n;
  3540 
  3555 
  3541     if (!__isStringLike(path)) {
  3556     if (!__isStringLike(encodedPathName)) {
  3542 	error = @symbol(badArgument1);
  3557         error = @symbol(badArgument1);
  3543 	goto err;
  3558         goto err;
  3544     }
  3559     }
  3545     if (!__isArrayLike(attributes)) {
  3560     if (!__isArrayLike(attributes)) {
  3546 	error = @symbol(badArgument2);
  3561         error = @symbol(badArgument2);
  3547 	goto err;
  3562         goto err;
  3548     }
  3563     }
  3549     if (modeInteger == nil) {
  3564     if (modeInteger == nil) {
  3550 	mode = 0644;
  3565         mode = 0644;
  3551     } else if (__isSmallInteger(modeInteger)) {
  3566     } else if (__isSmallInteger(modeInteger)) {
  3552 	mode = __intVal(modeInteger);
  3567         mode = __intVal(modeInteger);
  3553     } else {
  3568     } else {
  3554 	error = @symbol(badArgument3);
  3569         error = @symbol(badArgument3);
  3555 	goto err;
  3570         goto err;
  3556     }
  3571     }
  3557 
  3572 
  3558     nAttributes = __arraySize(attributes);
  3573     nAttributes = __arraySize(attributes);
  3559     for (n = 0, ap = __arrayVal(attributes); n < nAttributes; n++) {
  3574     for (n = 0, ap = __arrayVal(attributes); n < nAttributes; n++) {
  3560 	OBJ attribute = ap[n];
  3575         OBJ attribute = ap[n];
  3561 
  3576 
  3562 	if (attribute == @symbol(O_RDONLY)) {
  3577         if (attribute == @symbol(O_RDONLY)) {
  3563 	    openFlags |= O_RDONLY;
  3578             openFlags |= O_RDONLY;
  3564 	} else if (attribute == @symbol(O_RDWR)) {
  3579         } else if (attribute == @symbol(O_RDWR)) {
  3565 	    openFlags |= O_RDWR;
  3580             openFlags |= O_RDWR;
  3566 	} else if (attribute == @symbol(O_WRONLY)) {
  3581         } else if (attribute == @symbol(O_WRONLY)) {
  3567 	    openFlags |= O_WRONLY;
  3582             openFlags |= O_WRONLY;
  3568 	} else if (attribute == @symbol(O_CREAT)) {
  3583         } else if (attribute == @symbol(O_CREAT)) {
  3569 	    openFlags |= O_CREAT;
  3584             openFlags |= O_CREAT;
  3570 	} else if (attribute == @symbol(O_APPEND)) {
  3585         } else if (attribute == @symbol(O_APPEND)) {
  3571 	    openFlags |= O_APPEND;
  3586             openFlags |= O_APPEND;
  3572 	} else if (attribute == @symbol(O_EXCL)) {
  3587         } else if (attribute == @symbol(O_EXCL)) {
  3573 	    openFlags |= O_EXCL;
  3588             openFlags |= O_EXCL;
  3574 	} else if (attribute == @symbol(O_TRUNC)) {
  3589         } else if (attribute == @symbol(O_TRUNC)) {
  3575 	    openFlags |= O_TRUNC;
  3590             openFlags |= O_TRUNC;
  3576 	} else if (attribute == @symbol(O_LARGEFILE)) {
  3591         } else if (attribute == @symbol(O_LARGEFILE)) {
  3577 #ifdef O_LARGEFILE
  3592 #ifdef O_LARGEFILE
  3578 	    openFlags |= O_LARGEFILE;
  3593             openFlags |= O_LARGEFILE;
  3579 #else
  3594 #else
  3580 	    error = @symbol(badArgument2);
  3595             error = @symbol(badArgument2);
  3581 	    goto err;
  3596             goto err;
  3582 #endif
  3597 #endif
  3583 	} else if (attribute == @symbol(O_SYNC)) {
  3598         } else if (attribute == @symbol(O_SYNC)) {
  3584 #ifdef O_SYNC
  3599 #ifdef O_SYNC
  3585 	    openFlags |= O_SYNC;
  3600             openFlags |= O_SYNC;
  3586 #else
  3601 #else
  3587 	    error = @symbol(badArgument2);
  3602             error = @symbol(badArgument2);
  3588 	    goto err;
  3603             goto err;
  3589 #endif
  3604 #endif
  3590 	}
  3605         }
  3591     }
  3606     }
  3592 
  3607 
  3593 #if defined(O_NONBLOCK)
  3608 #if defined(O_NONBLOCK)
  3594     openFlags |= O_NONBLOCK;
  3609     openFlags |= O_NONBLOCK;
  3595 #elif defined(O_NDELAY)
  3610 #elif defined(O_NDELAY)
  3596     openFlags |= O_NDELAY;
  3611     openFlags |= O_NDELAY;
  3597 #endif
  3612 #endif
  3598 
  3613 
  3599 again:
  3614 again:
  3600     fd = open((char *) __stringVal(path), openFlags, mode);
  3615     fd = open((char *) __stringVal(encodedPathName), openFlags, mode);
  3601     if (fd < 0) {
  3616     if (fd < 0) {
  3602 	if (errno == EINTR) {
  3617         if (errno == EINTR) {
  3603 	    __HANDLE_INTERRUPTS__;
  3618             __HANDLE_INTERRUPTS__;
  3604 	    goto again;
  3619             goto again;
  3605 	} else {
  3620         } else {
  3606 	    error = __mkSmallInteger(errno);
  3621             error = __mkSmallInteger(errno);
  3607 	    goto err;
  3622             goto err;
  3608 	}
  3623         }
  3609     }
  3624     }
  3610     fileDescriptor = __mkSmallInteger(fd);
  3625     fileDescriptor = __mkSmallInteger(fd);
  3611 err:;
  3626 err:;
  3612 %}.
  3627 %}.
  3613     ^ fileDescriptor notNil ifTrue:[
  3628     ^ fileDescriptor notNil ifTrue:[
  3614 	FileDescriptorHandle for:fileDescriptor.
  3629         FileDescriptorHandle for:fileDescriptor.
  3615     ] ifFalse:[
  3630     ] ifFalse:[
  3616 	(self errorHolderForNumber:error) reportError
  3631         (self errorHolderForNumber:error) reportError
  3617     ].
  3632     ].
  3618 
  3633 
  3619     "
  3634     "
  3620 	self open:'/etc/hosts' attributes:#(O_RDONLY) mode:nil
  3635         self open:'/etc/hosts' attributes:#(O_RDONLY) mode:nil
  3621 	self open:'/tmp/xxzz' attributes:#(O_RDWR O_CREAT) mode:8r611
  3636         self open:'/tmp/xxzz' attributes:#(O_RDWR O_CREAT) mode:8r611
  3622 	self open:'/etc/passwd' attributes:#(O_RDWR) mode:nil
  3637         self open:'/etc/passwd' attributes:#(O_RDWR) mode:nil
  3623 	self open:'/no one knows this file' attributes:#(O_RDONLY) mode:nil
  3638         self open:'/no one knows this file' attributes:#(O_RDONLY) mode:nil
  3624 	self open:'foo/bar/baz' attributes:#(O_RDWR O_CREAT) mode:nil
  3639         self open:'foo/bar/baz' attributes:#(O_RDWR O_CREAT) mode:nil
  3625     "
  3640     "
  3626 !
  3641 !
  3627 
  3642 
  3628 openFileForAppend:pathName
  3643 openFileForAppend:pathName
  3629 
  3644 
  3677     "remove the directory named 'fullPathName'.
  3692     "remove the directory named 'fullPathName'.
  3678      The directory must be empty and you must have appropriate access rights.
  3693      The directory must be empty and you must have appropriate access rights.
  3679      Return true if successful, false if directory is not empty or no permission.
  3694      Return true if successful, false if directory is not empty or no permission.
  3680      This is a lowLevel entry - use Filename protocol for compatibility."
  3695      This is a lowLevel entry - use Filename protocol for compatibility."
  3681 
  3696 
       
  3697     |encodedPathName|
       
  3698 
       
  3699     encodedPathName := self encodePath:fullPathName.
  3682 %{
  3700 %{
  3683     int ret;
  3701     int ret;
  3684 
  3702 
  3685     if (__isStringLike(fullPathName)) {
  3703     if (__isStringLike(encodedPathName)) {
  3686 	__BEGIN_INTERRUPTABLE__
  3704         __BEGIN_INTERRUPTABLE__
  3687 	do {
  3705         do {
  3688 	    ret = rmdir((char *) __stringVal(fullPathName));
  3706             ret = rmdir((char *) __stringVal(encodedPathName));
  3689 	} while (ret < 0 && errno == EINTR);
  3707         } while (ret < 0 && errno == EINTR);
  3690 	__END_INTERRUPTABLE__
  3708         __END_INTERRUPTABLE__
  3691 	if (ret < 0) {
  3709         if (ret < 0) {
  3692 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3710             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3693 	    RETURN ( false );
  3711             RETURN ( false );
  3694 	}
  3712         }
  3695 	RETURN (true);
  3713         RETURN (true);
  3696     }
  3714     }
  3697 %}.
  3715 %}.
  3698     "/
  3716     "/
  3699     "/ either not a string argument,
  3717     "/ either not a string argument,
  3700     "/ or not supported by OS
  3718     "/ or not supported by OS
  3709 
  3727 
  3710 removeFile:fullPathName
  3728 removeFile:fullPathName
  3711     "remove the file named 'fullPathName'; return true if successful.
  3729     "remove the file named 'fullPathName'; return true if successful.
  3712      This is a lowLevel entry - use Filename protocol for compatibility."
  3730      This is a lowLevel entry - use Filename protocol for compatibility."
  3713 
  3731 
       
  3732     |encodedPathName|
       
  3733 
       
  3734     encodedPathName := self encodePath:fullPathName.
  3714 %{
  3735 %{
  3715     int ret;
  3736     int ret;
  3716 
  3737 
  3717     if (__isStringLike(fullPathName)) {
  3738     if (__isStringLike(encodedPathName)) {
  3718 	__BEGIN_INTERRUPTABLE__
  3739         __BEGIN_INTERRUPTABLE__
  3719 	do {
  3740         do {
  3720 	    ret = unlink((char *) __stringVal(fullPathName));
  3741             ret = unlink((char *) __stringVal(encodedPathName));
  3721 	} while (ret < 0 && errno == EINTR);
  3742         } while (ret < 0 && errno == EINTR);
  3722 	__END_INTERRUPTABLE__
  3743         __END_INTERRUPTABLE__
  3723 	if (ret < 0) {
  3744         if (ret < 0) {
  3724 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3745             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3725 	    RETURN ( false );
  3746             RETURN ( false );
  3726 	}
  3747         }
  3727 	RETURN (true);
  3748         RETURN (true);
  3728     }
  3749     }
  3729 %}.
  3750 %}.
  3730     ^ self primitiveFailed
  3751     ^ self primitiveFailed
  3731 !
  3752 !
  3732 
  3753 
  3736      correct for the OS used - therefore, this should not be called
  3757      correct for the OS used - therefore, this should not be called
  3737      directly. Instead, use Filename protocol to rename; this cares for
  3758      directly. Instead, use Filename protocol to rename; this cares for
  3738      any invalid names.
  3759      any invalid names.
  3739      Returns true if successful, false if not"
  3760      Returns true if successful, false if not"
  3740 
  3761 
       
  3762     |encodedOldPathName encodedNewPathName|
       
  3763 
       
  3764     encodedOldPathName := self encodePath:oldPath.
       
  3765     encodedNewPathName := self encodePath:newPath.
  3741 %{
  3766 %{
  3742     int ret, eno;
  3767     int ret, eno;
  3743 
  3768 
  3744     if (__isStringLike(oldPath) && __isStringLike(newPath)) {
  3769     if (__isStringLike(encodedOldPathName) && __isStringLike(encodedNewPathName)) {
  3745 #if defined(HAS_RENAME)
  3770 #if defined(HAS_RENAME)
  3746 	__BEGIN_INTERRUPTABLE__
  3771         __BEGIN_INTERRUPTABLE__
  3747 	do {
  3772         do {
  3748 	    ret = rename((char *) __stringVal(oldPath), (char *) __stringVal(newPath));
  3773             ret = rename((char *) __stringVal(encodedOldPathName), (char *) __stringVal(encodedNewPathName));
  3749 	} while (ret < 0 && errno == EINTR);
  3774         } while (ret < 0 && errno == EINTR);
  3750 	__END_INTERRUPTABLE__
  3775         __END_INTERRUPTABLE__
  3751 #else
  3776 #else
  3752 	ret = link((char *) __stringVal(oldPath), (char *) __stringVal(newPath));
  3777         ret = link((char *) __stringVal(encodedOldPathName), (char *) __stringVal(encodedNewPathName));
  3753 	if (ret >= 0) {
  3778         if (ret >= 0) {
  3754 	    ret = unlink((char *) __stringVal(oldPath));
  3779             ret = unlink((char *) __stringVal(encodedOldPathName));
  3755 	    if (ret < 0) {
  3780             if (ret < 0) {
  3756 		eno = errno;
  3781                 eno = errno;
  3757 		unlink((char *) __stringVal(newPath));
  3782                 unlink((char *) __stringVal(encodedNewPathName));
  3758 		errno = eno;
  3783                 errno = eno;
  3759 	    }
  3784             }
  3760 	}
  3785         }
  3761 #endif
  3786 #endif
  3762 	if (ret < 0) {
  3787         if (ret < 0) {
  3763 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3788             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3764 	    RETURN ( false );
  3789             RETURN ( false );
  3765 	}
  3790         }
  3766 	RETURN (true);
  3791         RETURN (true);
  3767     }
  3792     }
  3768 %}.
  3793 %}.
  3769     ^ self primitiveFailed
  3794     ^ self primitiveFailed
  3770 
  3795 
  3771     "
  3796     "
  3776 truncateFile:aPathName to:newSize
  3801 truncateFile:aPathName to:newSize
  3777     "change a files size return true on success, false on failure.
  3802     "change a files size return true on success, false on failure.
  3778      This may not be supported on all architectures.
  3803      This may not be supported on all architectures.
  3779 
  3804 
  3780      This is a low-level entry - use Filename protocol."
  3805      This is a low-level entry - use Filename protocol."
       
  3806 
       
  3807     |encodedPathName|
       
  3808 
       
  3809     encodedPathName := self encodePath:aPathName.
  3781 
  3810 
  3782 %{
  3811 %{
  3783 #if defined(HAS_TRUNCATE) || defined(HAS_FTRUNCATE)
  3812 #if defined(HAS_TRUNCATE) || defined(HAS_FTRUNCATE)
  3784     int ret;
  3813     int ret;
  3785     off_t truncateSize;
  3814     off_t truncateSize;
  3786 
  3815 
  3787     if (!__isStringLike(aPathName))
  3816     if (!__isStringLike(encodedPathName))
  3788 	goto getOutOfHere;
  3817         goto getOutOfHere;
  3789 
  3818 
  3790     if (__isSmallInteger(newSize)) {
  3819     if (__isSmallInteger(newSize)) {
  3791 	truncateSize = __intVal(newSize);
  3820         truncateSize = __intVal(newSize);
  3792 	if (truncateSize < 0) {
  3821         if (truncateSize < 0) {
  3793 	    goto getOutOfHere;
  3822             goto getOutOfHere;
  3794 	}
  3823         }
  3795     } else {
  3824     } else {
  3796 	truncateSize = __signedLongIntVal(newSize);
  3825         truncateSize = __signedLongIntVal(newSize);
  3797 	if (truncateSize < 0) {
  3826         if (truncateSize < 0) {
  3798 	    goto getOutOfHere;
  3827             goto getOutOfHere;
  3799 	}
  3828         }
  3800 	if (truncateSize == 0) {
  3829         if (truncateSize == 0) {
  3801 	    if (sizeof(truncateSize) == 8) {
  3830             if (sizeof(truncateSize) == 8) {
  3802 		if (__signedLong64IntVal(newSize, &truncateSize) == 0 || truncateSize < 0) {
  3831                 if (__signedLong64IntVal(newSize, &truncateSize) == 0 || truncateSize < 0) {
  3803 		    goto getOutOfHere;
  3832                     goto getOutOfHere;
  3804 		}
  3833                 }
  3805 	    } else {
  3834             } else {
  3806 		goto getOutOfHere;
  3835                 goto getOutOfHere;
  3807 	    }
  3836             }
  3808 	}
  3837         }
  3809     }
  3838     }
  3810 
  3839 
  3811 #if defined(HAS_TRUNCATE)
  3840 #if defined(HAS_TRUNCATE)
  3812 	__BEGIN_INTERRUPTABLE__
  3841         __BEGIN_INTERRUPTABLE__
  3813 	do {
  3842         do {
  3814 	    ret = truncate((char *) __stringVal(aPathName), truncateSize);
  3843             ret = truncate((char *) __stringVal(encodedPathName), truncateSize);
  3815 	} while (ret < 0 && errno == EINTR);
  3844         } while (ret < 0 && errno == EINTR);
  3816 	__END_INTERRUPTABLE__
  3845         __END_INTERRUPTABLE__
  3817 #else
  3846 #else
  3818 # ifdef HAS_FTRUNCATE
  3847 # ifdef HAS_FTRUNCATE
  3819     {
  3848     {
  3820 	int fd;
  3849         int fd;
  3821 
  3850 
  3822 	do {
  3851         do {
  3823 	    fd = open((char *) __stringVal(aPathName), 2);
  3852             fd = open((char *) __stringVal(encodedPathName), 2);
  3824 	} while (fd < 0 && errno == EINTR);
  3853         } while (fd < 0 && errno == EINTR);
  3825 	if (fd < 0) {
  3854         if (fd < 0) {
  3826 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3855             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3827 	    RETURN ( false );
  3856             RETURN ( false );
  3828 	}
  3857         }
  3829 
  3858 
  3830 	ret = ftruncate(fd, truncateSize);
  3859         ret = ftruncate(fd, truncateSize);
  3831 	close(fd);
  3860         close(fd);
  3832     }
  3861     }
  3833 # endif /* HAS_FTRUNCATE */
  3862 # endif /* HAS_FTRUNCATE */
  3834 #endif
  3863 #endif
  3835     if (ret < 0) {
  3864     if (ret < 0) {
  3836 	@global(LastErrorNumber) = __mkSmallInteger(errno);
  3865         @global(LastErrorNumber) = __mkSmallInteger(errno);
  3837 	RETURN ( false );
  3866         RETURN ( false );
  3838     }
  3867     }
  3839     RETURN (true);
  3868     RETURN (true);
  3840 getOutOfHere:;
  3869 getOutOfHere:;
  3841 #endif
  3870 #endif
  3842 %}.
  3871 %}.
  3920      Notice that the returned number is OS dependent - use the
  3949      Notice that the returned number is OS dependent - use the
  3921      modeMasks as returned by OperatingSystem>>accessMaskFor:"
  3950      modeMasks as returned by OperatingSystem>>accessMaskFor:"
  3922 
  3951 
  3923     "
  3952     "
  3924      this could have been implemented as:
  3953      this could have been implemented as:
  3925 	(self infoOf:aPathName) at:#mode
  3954         (self infoOf:aPathName) at:#mode
  3926      but for huge directory searches the code below is faster
  3955      but for huge directory searches the code below is faster
  3927     "
  3956     "
  3928 
  3957 
       
  3958     |encodedPathName|
       
  3959 
       
  3960     encodedPathName := self encodePath:aPathName.
  3929 %{
  3961 %{
  3930     struct stat buf;
  3962     struct stat buf;
  3931     int ret;
  3963     int ret;
  3932 
  3964 
  3933     if (__isStringLike(aPathName)) {
  3965     if (__isStringLike(encodedPathName)) {
  3934 # ifdef TRACE_STAT_CALLS
  3966 # ifdef TRACE_STAT_CALLS
  3935 	printf("stat on '%s' for accessMode\n", __stringVal(aPathName));
  3967         printf("stat on '%s' for accessMode\n", __stringVal(encodedPathName));
  3936 # endif
  3968 # endif
  3937 	__BEGIN_INTERRUPTABLE__
  3969         __BEGIN_INTERRUPTABLE__
  3938 	do {
  3970         do {
  3939 	    ret = stat((char *) __stringVal(aPathName), &buf);
  3971             ret = stat((char *) __stringVal(encodedPathName), &buf);
  3940 	} while ((ret < 0) && (errno == EINTR));
  3972         } while ((ret < 0) && (errno == EINTR));
  3941 	__END_INTERRUPTABLE__
  3973         __END_INTERRUPTABLE__
  3942 
  3974 
  3943 	if (ret < 0) {
  3975         if (ret < 0) {
  3944 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  3976             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3945 	    RETURN ( nil );
  3977             RETURN ( nil );
  3946 	}
  3978         }
  3947 	RETURN ( __mkSmallInteger(buf.st_mode & 0777) );
  3979         RETURN ( __mkSmallInteger(buf.st_mode & 0777) );
  3948     }
  3980     }
  3949 %}.
  3981 %}.
  3950    ^ self primitiveFailed
  3982    ^ self primitiveFailed
  3951 
  3983 
  3952    "
  3984    "
  3958     "change the access rights of aPathName to the OS dependent modeBits.
  3990     "change the access rights of aPathName to the OS dependent modeBits.
  3959      You should construct this mask using accessMaskFor, to be OS
  3991      You should construct this mask using accessMaskFor, to be OS
  3960      independent. Return true if changed,
  3992      independent. Return true if changed,
  3961      false if such a file does not exist or change was not allowd."
  3993      false if such a file does not exist or change was not allowd."
  3962 
  3994 
       
  3995     |encodedPathName|
       
  3996 
       
  3997     encodedPathName := self encodePath:aPathName.
  3963 %{
  3998 %{
  3964     int ret;
  3999     int ret;
  3965 
  4000 
  3966     if (__isStringLike(aPathName) && __isSmallInteger(modeBits)) {
  4001     if (__isStringLike(encodedPathName) && __isSmallInteger(modeBits)) {
  3967 	__BEGIN_INTERRUPTABLE__
  4002         __BEGIN_INTERRUPTABLE__
  3968 	do {
  4003         do {
  3969 	    ret = chmod((char *)__stringVal(aPathName), __intVal(modeBits));
  4004             ret = chmod((char *)__stringVal(encodedPathName), __intVal(modeBits));
  3970 	} while (ret < 0 && errno == EINTR);
  4005         } while (ret < 0 && errno == EINTR);
  3971 	__END_INTERRUPTABLE__
  4006         __END_INTERRUPTABLE__
  3972 	if (ret < 0) {
  4007         if (ret < 0) {
  3973 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  4008             @global(LastErrorNumber) = __mkSmallInteger(errno);
  3974 	    RETURN ( false );
  4009             RETURN ( false );
  3975 	}
  4010         }
  3976 	RETURN ( true );
  4011         RETURN ( true );
  3977     }
  4012     }
  3978 %}.
  4013 %}.
  3979     ^ self primitiveFailed
  4014     ^ self primitiveFailed
  3980 ! !
  4015 ! !
  3981 
  4016 
  4291     "return the name of the current directory"
  4326     "return the name of the current directory"
  4292 
  4327 
  4293     |path|
  4328     |path|
  4294 
  4329 
  4295 %{  /* UNLIMITEDSTACK */
  4330 %{  /* UNLIMITEDSTACK */
  4296 	char nameBuffer[MAXPATHLEN + 1];
  4331         char nameBuffer[MAXPATHLEN + 1];
  4297 
  4332 
  4298 	if (getcwd(nameBuffer, MAXPATHLEN)) {
  4333         if (getcwd(nameBuffer, MAXPATHLEN)) {
  4299 	    OBJ d;
  4334             path = __MKSTRING(nameBuffer);
  4300 
  4335         }
  4301 	    @global(CurrentDirectory) = d = __MKSTRING(nameBuffer);
       
  4302 	    __GSTORE(d);
       
  4303 	    RETURN (d);
       
  4304 	}
       
  4305 %}.
  4336 %}.
  4306     ^ self primitiveFailed
  4337     path isNil ifTrue:[
  4307 
  4338         ^ self primitiveFailed.
  4308     "
  4339     ].
  4309 	self getCurrentDirectory
  4340     path := self decodePath:path.
       
  4341     CurrentDirectory := path.
       
  4342 
       
  4343     ^ path.
       
  4344 
       
  4345     "
       
  4346         self getCurrentDirectory
  4310     "
  4347     "
  4311 !
  4348 !
  4312 
  4349 
  4313 getDiskInfoOf:aDirectoryPath
  4350 getDiskInfoOf:aDirectoryPath
  4314     "return some disk info.
  4351     "return some disk info.
  4464 
  4501 
  4465 infoOf:aPathName
  4502 infoOf:aPathName
  4466     "return some object filled with info for the file 'aPathName';
  4503     "return some object filled with info for the file 'aPathName';
  4467      the info (for which corresponding access methods are understood by
  4504      the info (for which corresponding access methods are understood by
  4468      the returned object) is:
  4505      the returned object) is:
  4469 	 type            - a symbol giving the files type
  4506          type            - a symbol giving the files type
  4470 	 mode            - numeric access mode
  4507          mode            - numeric access mode
  4471 	 uid             - owners user id
  4508          uid             - owners user id
  4472 	 gid             - owners group id
  4509          gid             - owners group id
  4473 	 size            - files size
  4510          size            - files size
  4474 	 id              - files number (i.e. inode number)
  4511          id              - files number (i.e. inode number)
  4475 	 accessed        - last access time (as Timestamp)
  4512          accessed        - last access time (as Timestamp)
  4476 	 modified        - last modification time (as Timestamp)
  4513          modified        - last modification time (as Timestamp)
  4477 	 statusChanged   - last status change time (as Timestamp)
  4514          statusChanged   - last status change time (as Timestamp)
  4478 	 alternativeName     - (windows only:) the MSDOS name of the file
  4515          alternativeName     - (windows only:) the MSDOS name of the file
  4479 	 recordFormatNumeric - (VMS only:) numeric value of the recordFormat
  4516          recordFormatNumeric - (VMS only:) numeric value of the recordFormat
  4480 	 recordFormat        - (VMS only:) symbolic value of the recordFormat
  4517          recordFormat        - (VMS only:) symbolic value of the recordFormat
  4481 	 recordAttributes    - (VMS only:) recordAttributes
  4518          recordAttributes    - (VMS only:) recordAttributes
  4482 	 fixedHeaderSize     - (VMS only:) fixed header size in a variable record format
  4519          fixedHeaderSize     - (VMS only:) fixed header size in a variable record format
  4483 	 recordSize          - (VMS only:) record size.
  4520          recordSize          - (VMS only:) record size.
  4484 
  4521 
  4485      Some of the fields may be returned as nil on systems which do not provide
  4522      Some of the fields may be returned as nil on systems which do not provide
  4486      all of the information.
  4523      all of the information.
  4487      Return nil if such a file does not exist.
  4524      Return nil if such a file does not exist.
  4488      For symbolic links (if supported by the OS),
  4525      For symbolic links (if supported by the OS),
  4489      the info of the pointed-to-file (i.e. the target) is returned;
  4526      the info of the pointed-to-file (i.e. the target) is returned;
  4490      use #linkInfoOf: to get info about the link itself.
  4527      use #linkInfoOf: to get info about the link itself.
  4491     "
  4528     "
  4492 
  4529 
  4493     |type mode uid gid size id nLink aOStime mOStime cOStime error|
  4530     |type mode uid gid size id nLink aOStime mOStime cOStime error encodedPathName|
       
  4531 
       
  4532     encodedPathName := self encodePath:aPathName.
  4494 %{
  4533 %{
  4495     struct stat buf;
  4534     struct stat buf;
  4496     int ret;
  4535     int ret;
  4497 
  4536 
  4498     if (!__isStringLike(aPathName)) {
  4537     if (!__isStringLike(encodedPathName)) {
  4499 	error = @symbol(badArgument);
  4538         error = @symbol(badArgument);
  4500 	goto out;
  4539         goto out;
  4501     }
  4540     }
  4502 
  4541 
  4503 # ifdef TRACE_STAT_CALLS
  4542 # ifdef TRACE_STAT_CALLS
  4504     printf("stat on '%s' for info\n", __stringVal(aPathName));
  4543     printf("stat on '%s' for info\n", __stringVal(aPathName));
  4505 # endif
  4544 # endif
  4506     __BEGIN_INTERRUPTABLE__
  4545     __BEGIN_INTERRUPTABLE__
  4507     do {
  4546     do {
  4508 	ret = stat((char *) __stringVal(aPathName), &buf);
  4547         ret = stat((char *) __stringVal(encodedPathName), &buf);
  4509     } while ((ret < 0) && (errno == EINTR));
  4548     } while ((ret < 0) && (errno == EINTR));
  4510     __END_INTERRUPTABLE__
  4549     __END_INTERRUPTABLE__
  4511 
  4550 
  4512     if (ret < 0) {
  4551     if (ret < 0) {
  4513 	error = __mkSmallInteger(errno);
  4552         error = __mkSmallInteger(errno);
  4514 	@global(LastErrorNumber) = error;
  4553         @global(LastErrorNumber) = error;
  4515 	goto out;
  4554         goto out;
  4516     }
  4555     }
  4517     switch (buf.st_mode & S_IFMT) {
  4556     switch (buf.st_mode & S_IFMT) {
  4518 	case S_IFDIR:
  4557         case S_IFDIR:
  4519 	    type = @symbol(directory);
  4558             type = @symbol(directory);
  4520 	    break;
  4559             break;
  4521 
  4560 
  4522 	case S_IFREG:
  4561         case S_IFREG:
  4523 	    type = @symbol(regular);
  4562             type = @symbol(regular);
  4524 	    break;
  4563             break;
  4525 # ifdef S_IFCHR
  4564 # ifdef S_IFCHR
  4526 	case S_IFCHR:
  4565         case S_IFCHR:
  4527 	    type = @symbol(characterSpecial);
  4566             type = @symbol(characterSpecial);
  4528 	    break;
  4567             break;
  4529 # endif
  4568 # endif
  4530 # ifdef S_IFBLK
  4569 # ifdef S_IFBLK
  4531 	case S_IFBLK:
  4570         case S_IFBLK:
  4532 	    type = @symbol(blockSpecial);
  4571             type = @symbol(blockSpecial);
  4533 	    break;
  4572             break;
  4534 # endif
  4573 # endif
  4535 # ifdef S_IFMPC
  4574 # ifdef S_IFMPC
  4536 	case S_IFMPC:
  4575         case S_IFMPC:
  4537 	    type = @symbol(multiplexedCharacterSpecial);
  4576             type = @symbol(multiplexedCharacterSpecial);
  4538 	    break;
  4577             break;
  4539 # endif
  4578 # endif
  4540 # ifdef S_IFMPB
  4579 # ifdef S_IFMPB
  4541 	case S_IFMPB:
  4580         case S_IFMPB:
  4542 	    type = @symbol(multiplexedBlockSpecial);
  4581             type = @symbol(multiplexedBlockSpecial);
  4543 	    break;
  4582             break;
  4544 # endif
  4583 # endif
  4545 # ifdef S_IFLNK
  4584 # ifdef S_IFLNK
  4546 	case S_IFLNK:
  4585         case S_IFLNK:
  4547 	    type = @symbol(symbolicLink);
  4586             type = @symbol(symbolicLink);
  4548 	    break;
  4587             break;
  4549 # endif
  4588 # endif
  4550 # ifdef S_IFSOCK
  4589 # ifdef S_IFSOCK
  4551 	case S_IFSOCK:
  4590         case S_IFSOCK:
  4552 	    type = @symbol(socket);
  4591             type = @symbol(socket);
  4553 	    break;
  4592             break;
  4554 # endif
  4593 # endif
  4555 # ifdef S_IFIFO
  4594 # ifdef S_IFIFO
  4556 	case S_IFIFO:
  4595         case S_IFIFO:
  4557 	    type = @symbol(fifo);
  4596             type = @symbol(fifo);
  4558 	    break;
  4597             break;
  4559 # endif
  4598 # endif
  4560 	default:
  4599         default:
  4561 	    type = @symbol(unknown);
  4600             type = @symbol(unknown);
  4562 	    break;
  4601             break;
  4563     }
  4602     }
  4564 
  4603 
  4565     if (sizeof(buf.st_ino) == 8) {
  4604     if (sizeof(buf.st_ino) == 8) {
  4566 	id = __MKUINT64(&buf.st_ino);
  4605         id = __MKUINT64(&buf.st_ino);
  4567     } else {
  4606     } else {
  4568 	id = __MKUINT(buf.st_ino);
  4607         id = __MKUINT(buf.st_ino);
  4569     }
  4608     }
  4570     mode = __mkSmallInteger(buf.st_mode & 0777);
  4609     mode = __mkSmallInteger(buf.st_mode & 0777);
  4571     uid = __mkSmallInteger(buf.st_uid);
  4610     uid = __mkSmallInteger(buf.st_uid);
  4572     gid = __mkSmallInteger(buf.st_gid);
  4611     gid = __mkSmallInteger(buf.st_gid);
  4573     nLink = __mkSmallInteger(buf.st_nlink);
  4612     nLink = __mkSmallInteger(buf.st_nlink);
  4574     if (sizeof(buf.st_size) == 8) {
  4613     if (sizeof(buf.st_size) == 8) {
  4575 	size = __MKINT64(&buf.st_size);
  4614         size = __MKINT64(&buf.st_size);
  4576     } else {
  4615     } else {
  4577 	size = __MKINT(buf.st_size);
  4616         size = __MKINT(buf.st_size);
  4578     }
  4617     }
  4579     aOStime = __MKUINT(buf.st_atime);
  4618     aOStime = __MKUINT(buf.st_atime);
  4580     mOStime = __MKUINT(buf.st_mtime);
  4619     mOStime = __MKUINT(buf.st_mtime);
  4581     cOStime = __MKUINT(buf.st_ctime);
  4620     cOStime = __MKUINT(buf.st_ctime);
  4582 
  4621 
  4583     out:;
  4622     out:;
  4584 %}.
  4623 %}.
  4585      mode notNil ifTrue:[
  4624      mode notNil ifTrue:[
  4586 	"/ now done lazy in FileStatusInfo
  4625         "/ now done lazy in FileStatusInfo
  4587 	"/ atime := Timestamp fromOSTime:(aOStime * 1000).
  4626         "/ atime := Timestamp fromOSTime:(aOStime * 1000).
  4588 	"/ mtime := Timestamp fromOSTime:(mOStime * 1000).
  4627         "/ mtime := Timestamp fromOSTime:(mOStime * 1000).
  4589 	"/ ctime := Timestamp fromOSTime:(cOStime * 1000).
  4628         "/ ctime := Timestamp fromOSTime:(cOStime * 1000).
  4590 
  4629 
  4591 	^ FileStatusInfo
  4630         ^ FileStatusInfo
  4592 		    type:type
  4631                     type:type
  4593 		    mode:mode
  4632                     mode:mode
  4594 		    uid:uid
  4633                     uid:uid
  4595 		    gid:gid
  4634                     gid:gid
  4596 		    size:size
  4635                     size:size
  4597 		    id:id
  4636                     id:id
  4598 		    accessed:aOStime
  4637                     accessed:aOStime
  4599 		    modified:mOStime
  4638                     modified:mOStime
  4600 		    statusChanged:cOStime
  4639                     statusChanged:cOStime
  4601 		    path:nil
  4640                     path:nil
  4602 		    numLinks:nLink.
  4641                     numLinks:nLink.
  4603     ].
  4642     ].
  4604     error notNil ifTrue:[
  4643     error notNil ifTrue:[
  4605 	^ nil.
  4644         ^ nil.
  4606     ].
  4645     ].
  4607 
  4646 
  4608     ^ self primitiveFailed
  4647     ^ self primitiveFailed
  4609 
  4648 
  4610    "
  4649    "
  4618     "return true, if 'aPathName' is a valid directory path name.
  4657     "return true, if 'aPathName' is a valid directory path name.
  4619      (i.e. exists and is a directory).
  4658      (i.e. exists and is a directory).
  4620      This also returns true for symbolic links pointing to a directory;
  4659      This also returns true for symbolic links pointing to a directory;
  4621      if you need to check for this, use #linkInfo:."
  4660      if you need to check for this, use #linkInfo:."
  4622 
  4661 
       
  4662     |encodedPathName|
       
  4663 
       
  4664     encodedPathName := self encodePath:aPathName.
       
  4665 
  4623 %{
  4666 %{
  4624     int ret;
  4667     int ret;
  4625 
  4668 
  4626     if (__isStringLike(aPathName)) {
  4669     if (__isStringLike(encodedPathName)) {
  4627 	struct stat buf;
  4670         struct stat buf;
  4628 
  4671 
  4629 # ifdef TRACE_STAT_CALLS
  4672 # ifdef TRACE_STAT_CALLS
  4630 	printf("stat on '%s' for isDirectory\n", __stringVal(aPathName));
  4673         printf("stat on '%s' for isDirectory\n", __stringVal(encodedPathName));
  4631 # endif
  4674 # endif
  4632 	__BEGIN_INTERRUPTABLE__
  4675         __BEGIN_INTERRUPTABLE__
  4633 	do {
  4676         do {
  4634 	    ret = stat((char *) __stringVal(aPathName), &buf);
  4677             ret = stat((char *) __stringVal(encodedPathName), &buf);
  4635 	} while ((ret < 0) && (errno == EINTR));
  4678         } while ((ret < 0) && (errno == EINTR));
  4636 	__END_INTERRUPTABLE__
  4679         __END_INTERRUPTABLE__
  4637 	if (ret < 0) {
  4680         if (ret < 0) {
  4638 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  4681             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4639 	    RETURN ( false );
  4682             RETURN ( false );
  4640 	}
  4683         }
  4641 	RETURN ( ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false);
  4684         RETURN ( ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false);
  4642     }
  4685     }
  4643 %}.
  4686 %}.
  4644     ^ self primitiveFailed
  4687     ^ self primitiveFailed
  4645 
  4688 
  4646     "an alternative implementation would be:
  4689     "an alternative implementation would be:
  4647 	^ (self infoOf:aPathName) type == #directory
  4690         ^ (self infoOf:aPathName) type == #directory
  4648     "
  4691     "
  4649 !
  4692 !
  4650 
  4693 
  4651 isExecutable:aPathName
  4694 isExecutable:aPathName
  4652     "return true, if the given file is executable.
  4695     "return true, if the given file is executable.
  4653      For symbolic links, the pointed-to-file is checked."
  4696      For symbolic links, the pointed-to-file is checked."
  4654 
  4697 
       
  4698     |encodedPathName|
       
  4699 
       
  4700     encodedPathName := self encodePath:aPathName.
       
  4701 
  4655 %{
  4702 %{
  4656     int ret;
  4703     int ret;
  4657 
  4704 
  4658     if (__isStringLike(aPathName)) {
  4705     if (__isStringLike(encodedPathName)) {
  4659 # ifdef TRACE_ACCESS_CALLS
  4706 # ifdef TRACE_ACCESS_CALLS
  4660 	printf("access on '%s' for executable\n", __stringVal(aPathName));
  4707         printf("access on '%s' for executable\n", __stringVal(encodedPathName));
  4661 # endif
  4708 # endif
  4662 	__BEGIN_INTERRUPTABLE__
  4709         __BEGIN_INTERRUPTABLE__
  4663 	do {
  4710         do {
  4664 	    ret = access(__stringVal(aPathName), X_OK);
  4711             ret = access(__stringVal(encodedPathName), X_OK);
  4665 	} while ((ret < 0) && (errno == EINTR));
  4712         } while ((ret < 0) && (errno == EINTR));
  4666 	__END_INTERRUPTABLE__
  4713         __END_INTERRUPTABLE__
  4667 	if (ret < 0) {
  4714         if (ret < 0) {
  4668 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  4715             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4669 	}
  4716         }
  4670 	RETURN ( ((ret == 0) ? true : false) );
  4717         RETURN ( ((ret == 0) ? true : false) );
  4671     }
  4718     }
  4672 %}.
  4719 %}.
  4673     ^ self primitiveFailed
  4720     ^ self primitiveFailed
  4674 !
  4721 !
  4675 
  4722 
  4676 isReadable:aPathName
  4723 isReadable:aPathName
  4677     "return true, if the file/dir 'aPathName' is readable.
  4724     "return true, if the file/dir 'aPathName' is readable.
  4678      For symbolic links, the pointed-to-file is checked."
  4725      For symbolic links, the pointed-to-file is checked."
  4679 
  4726 
       
  4727     |encodedPathName|
       
  4728 
       
  4729     encodedPathName := self encodePath:aPathName.
  4680 %{
  4730 %{
  4681     int ret;
  4731     int ret;
  4682 
  4732 
  4683     if (__isStringLike(aPathName)) {
  4733     if (__isStringLike(encodedPathName)) {
  4684 # ifdef TRACE_ACCESS_CALLS
  4734 # ifdef TRACE_ACCESS_CALLS
  4685 	printf("access on '%s' for readable\n", __stringVal(aPathName));
  4735         printf("access on '%s' for readable\n", __stringVal(encodedPathName));
  4686 # endif
  4736 # endif
  4687 	__BEGIN_INTERRUPTABLE__
  4737         __BEGIN_INTERRUPTABLE__
  4688 	do {
  4738         do {
  4689 	    ret = access(__stringVal(aPathName), R_OK);
  4739             ret = access(__stringVal(encodedPathName), R_OK);
  4690 	} while ((ret < 0) && (errno == EINTR));
  4740         } while ((ret < 0) && (errno == EINTR));
  4691 	__END_INTERRUPTABLE__
  4741         __END_INTERRUPTABLE__
  4692 	if (ret < 0) {
  4742         if (ret < 0) {
  4693 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  4743             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4694 	}
  4744         }
  4695 	RETURN ( ((ret == 0) ? true : false) );
  4745         RETURN ( ((ret == 0) ? true : false) );
  4696     }
  4746     }
  4697 %}.
  4747 %}.
  4698     ^ self primitiveFailed
  4748     ^ self primitiveFailed
  4699 !
  4749 !
  4700 
  4750 
  4701 isValidPath:aPathName
  4751 isValidPath:aPathName
  4702     "return true, if 'aPathName' is a valid path name
  4752     "return true, if 'aPathName' is a valid path name
  4703      (i.e. the file or directory exists)"
  4753      (i.e. the file or directory exists)"
  4704 
  4754 
       
  4755     |encodedPathName|
       
  4756 
       
  4757     encodedPathName := self encodePath:aPathName.
  4705 %{
  4758 %{
  4706     struct stat buf;
  4759     struct stat buf;
  4707     int ret;
  4760     int ret;
  4708 
  4761 
  4709     if (__isStringLike(aPathName)) {
  4762     if (__isStringLike(encodedPathName)) {
  4710 # ifdef TRACE_STAT_CALLS
  4763 # ifdef TRACE_STAT_CALLS
  4711 	printf("stat on '%s' for isValidPath\n", __stringVal(aPathName));
  4764         printf("stat on '%s' for isValidPath\n", __stringVal(encodedPathName));
  4712 # endif
  4765 # endif
  4713 	__BEGIN_INTERRUPTABLE__
  4766         __BEGIN_INTERRUPTABLE__
  4714 	do {
  4767         do {
  4715 	    ret = stat((char *) __stringVal(aPathName), &buf);
  4768             ret = stat((char *) __stringVal(encodedPathName), &buf);
  4716 	} while ((ret < 0) && (errno == EINTR));
  4769         } while ((ret < 0) && (errno == EINTR));
  4717 	__END_INTERRUPTABLE__
  4770         __END_INTERRUPTABLE__
  4718 	if (ret < 0) {
  4771         if (ret < 0) {
  4719 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  4772             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4720 	    RETURN (false);
  4773             RETURN (false);
  4721 	}
  4774         }
  4722 	RETURN ( ret ? false : true );
  4775         RETURN ( ret ? false : true );
  4723     }
  4776     }
  4724 %}.
  4777 %}.
  4725     ^ self primitiveFailed
  4778     ^ self primitiveFailed
  4726 
  4779 
  4727 "/ alternative:
  4780 "/ alternative:
  4730 
  4783 
  4731 isWritable:aPathName
  4784 isWritable:aPathName
  4732     "return true, if the given file is writable.
  4785     "return true, if the given file is writable.
  4733      For symbolic links, the pointed-to-file is checked."
  4786      For symbolic links, the pointed-to-file is checked."
  4734 
  4787 
       
  4788     |encodedPathName|
       
  4789 
       
  4790     encodedPathName := self encodePath:aPathName.
  4735 %{
  4791 %{
  4736     int ret;
  4792     int ret;
  4737 
  4793 
  4738     if (__isStringLike(aPathName)) {
  4794     if (__isStringLike(encodedPathName)) {
  4739 # ifdef TRACE_ACCESS_CALLS
  4795 # ifdef TRACE_ACCESS_CALLS
  4740 	printf("access on '%s' for writable\n", __stringVal(aPathName));
  4796         printf("access on '%s' for writable\n", __stringVal(encodedPathName));
  4741 # endif
  4797 # endif
  4742 	__BEGIN_INTERRUPTABLE__
  4798         __BEGIN_INTERRUPTABLE__
  4743 	do {
  4799         do {
  4744 	    ret = access(__stringVal(aPathName), W_OK);
  4800             ret = access(__stringVal(encodedPathName), W_OK);
  4745 	} while ((ret < 0) && (errno == EINTR));
  4801         } while ((ret < 0) && (errno == EINTR));
  4746 	__END_INTERRUPTABLE__
  4802         __END_INTERRUPTABLE__
  4747 	if (ret < 0) {
  4803         if (ret < 0) {
  4748 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  4804             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4749 	}
  4805         }
  4750 	RETURN ( ((ret == 0) ? true : false) );
  4806         RETURN ( ((ret == 0) ? true : false) );
  4751     }
  4807     }
  4752 %}.
  4808 %}.
  4753     ^ self primitiveFailed
  4809     ^ self primitiveFailed
  4754 !
  4810 !
  4755 
  4811 
  4782 
  4838 
  4783      Return the info about the link itself,
  4839      Return the info about the link itself,
  4784      on contrast to #infoOf:, which returns the info of the pointed to file
  4840      on contrast to #infoOf:, which returns the info of the pointed to file
  4785      in case of a symbolic link."
  4841      in case of a symbolic link."
  4786 
  4842 
  4787     |type mode uid gid size id nLink aOStime mOStime cOStime path|
  4843     |type mode uid gid size id nLink aOStime mOStime cOStime path encodedPathName|
       
  4844 
       
  4845     encodedPathName := self encodePath:aPathName.
  4788 
  4846 
  4789 %{  /* STACK: 1200 */
  4847 %{  /* STACK: 1200 */
  4790 #if defined(S_IFLNK)
  4848 #if defined(S_IFLNK)
  4791     struct stat buf;
  4849     struct stat buf;
  4792     int ret;
  4850     int ret;
  4793     char pathBuffer[1024];
  4851     char pathBuffer[1024];
  4794 
  4852 
  4795     if (__isStringLike(aPathName)) {
  4853     if (__isStringLike(encodedPathName)) {
  4796         __BEGIN_INTERRUPTABLE__
  4854         __BEGIN_INTERRUPTABLE__
  4797         do {
  4855         do {
  4798             ret = lstat((char *) __stringVal(aPathName), &buf);
  4856             ret = lstat((char *) __stringVal(encodedPathName), &buf);
  4799         } while ((ret < 0) && (errno == EINTR));
  4857         } while ((ret < 0) && (errno == EINTR));
  4800         __END_INTERRUPTABLE__
  4858         __END_INTERRUPTABLE__
  4801 
  4859 
  4802         if (ret < 0) {
  4860         if (ret < 0) {
  4803             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4861             @global(LastErrorNumber) = __mkSmallInteger(errno);
  4805         }
  4863         }
  4806         switch (buf.st_mode & S_IFMT) {
  4864         switch (buf.st_mode & S_IFMT) {
  4807     # ifdef S_IFLNK
  4865     # ifdef S_IFLNK
  4808             case S_IFLNK:
  4866             case S_IFLNK:
  4809                 type = @symbol(symbolicLink);
  4867                 type = @symbol(symbolicLink);
  4810                 if ((ret = readlink((char *) __stringVal(aPathName), pathBuffer, sizeof(pathBuffer))) < 0) {
  4868                 if ((ret = readlink((char *) __stringVal(encodedPathName), pathBuffer, sizeof(pathBuffer))) < 0) {
  4811                     @global(LastErrorNumber) = __mkSmallInteger(errno);
  4869                     @global(LastErrorNumber) = __mkSmallInteger(errno);
  4812                     RETURN ( nil );
  4870                     RETURN ( nil );
  4813                 }
  4871                 }
  4814                 pathBuffer[ret] = '\0';  /* readlink does not 0-terminate */
  4872                 pathBuffer[ret] = '\0';  /* readlink does not 0-terminate */
  4815                 path = __MKSTRING(pathBuffer);
  4873                 path = __MKSTRING(pathBuffer);
  4878 #else
  4936 #else
  4879     RETURN ( nil );
  4937     RETURN ( nil );
  4880 #endif
  4938 #endif
  4881 %}.
  4939 %}.
  4882 
  4940 
  4883     path notNil ifTrue:[
       
  4884         [
       
  4885             path := path utf8Decoded.
       
  4886         ] on:InvalidEncodingError do:[:ex|
       
  4887             "maybe there are old filenames in ISO8859-x,
       
  4888              just keep them untranslated"
       
  4889         ].
       
  4890     ].
       
  4891     
       
  4892     mode notNil ifTrue:[
  4941     mode notNil ifTrue:[
  4893         ^ FileStatusInfo
  4942         ^ FileStatusInfo
  4894             type:type
  4943             type:type
  4895             mode:mode
  4944             mode:mode
  4896             uid:uid
  4945             uid:uid
  4898             size:size
  4947             size:size
  4899             id:id
  4948             id:id
  4900             accessed:aOStime
  4949             accessed:aOStime
  4901             modified:mOStime
  4950             modified:mOStime
  4902             statusChanged:cOStime
  4951             statusChanged:cOStime
  4903             path:path
  4952             path:(self decodePath:path)
  4904             numLinks:nLink.
  4953             numLinks:nLink.
  4905    ].
  4954    ].
  4906    ^ self primitiveFailed
  4955    ^ self primitiveFailed
  4907 
  4956 
  4908    "
  4957    "
  4955      Notice: if symbolic links are involved, the result may look different
  5004      Notice: if symbolic links are involved, the result may look different
  4956      from what you expect."
  5005      from what you expect."
  4957 
  5006 
  4958     |p path command|
  5007     |p path command|
  4959 
  5008 
       
  5009     path = '.' ifTrue:[
       
  5010         ^ self getCurrentDirectory.
       
  5011     ].
       
  5012 
  4960     "some systems have a convenient function for this ..."
  5013     "some systems have a convenient function for this ..."
  4961     path := self primPathNameOf:pathName.
  5014     path := self primPathNameOf:(self encodePath:pathName).
  4962 
  5015 
  4963     path isNil ifTrue:[
  5016     path isNil ifTrue:[
  4964 	(self isValidPath:pathName) ifFalse:[
  5017         (self isValidPath:pathName) ifFalse:[
  4965 	    p := pathName.
  5018             p := pathName.
  4966 	    [(p size > 1)
  5019             [(p size > 1)
  4967 	     and:[p endsWith:(self fileSeparator)]
  5020              and:[p endsWith:(self fileSeparator)]
  4968 	    ] whileTrue:[
  5021             ] whileTrue:[
  4969 		p := p copyWithoutLast:1.
  5022                 p := p copyWithoutLast:1.
  4970 	    ].
  5023             ].
  4971 	    ^ p
  5024             ^ p
  4972 	].
  5025         ].
  4973 
  5026 
  4974 	(SlowFork==true or:[PipeFailed==true]) ifFalse:[
  5027         (SlowFork==true or:[PipeFailed==true]) ifFalse:[
  4975 	    PipeStream openErrorSignal handle:[:ex |
  5028             PipeStream openErrorSignal handle:[:ex |
  4976 		PipeFailed := true.
  5029                 PipeFailed := true.
  4977 		'UnixOperatingSystem [warning]: cannot fork/popen' errorPrintCR.
  5030                 'UnixOperatingSystem [warning]: cannot fork/popen' errorPrintCR.
  4978 		ex return.
  5031                 ex return.
  4979 	    ] do:[
  5032             ] do:[
  4980 		"have to fall back ..."
  5033                 "have to fall back ..."
  4981 		command := 'cd "' , pathName , '"; pwd'.
  5034                 command := 'cd "' , pathName , '"; pwd'.
  4982 		p := PipeStream readingFrom:command.
  5035                 p := PipeStream readingFrom:command.
  4983 	    ].
  5036             ].
  4984 
  5037 
  4985 	    (p isNil or:[p atEnd]) ifTrue:[
  5038             (p isNil or:[p atEnd]) ifTrue:[
  4986 		('UnixOperatingSystem [warning]: PipeStream for <' , command , '> failed') errorPrintCR.
  5039                 ('UnixOperatingSystem [warning]: PipeStream for <' , command , '> failed') errorPrintCR.
  4987 	    ] ifFalse:[
  5040             ] ifFalse:[
  4988 		path := p nextLine.
  5041                 path := p nextLine.
  4989 		p close.
  5042                 p close.
  4990 	    ]
  5043             ]
  4991 	].
  5044         ].
  4992 	path isNil ifTrue:[
  5045         path isNil ifTrue:[
  4993 	    "/
  5046             "/
  4994 	    "/ return the original - there is nothing else can we do
  5047             "/ return the original - there is nothing else can we do
  4995 	    "/
  5048             "/
  4996 	    path := pathName
  5049             path := pathName
  4997 	].
  5050         ].
  4998 	(SlowFork==true or:[ForkFailed==true]) ifTrue:[
  5051         (SlowFork==true or:[ForkFailed==true]) ifTrue:[
  4999 	    path := self compressPath:path
  5052             path := self compressPath:path
  5000 	]
  5053         ]
  5001     ].
  5054     ].
  5002     ^ path.
  5055     ^ path.
  5003 
  5056 
  5004     "
  5057     "
  5005      OperatingSystem pathNameOf:'.'
  5058      OperatingSystem pathNameOf:'.'
  5017 !
  5070 !
  5018 
  5071 
  5019 primIdOf:aPathName
  5072 primIdOf:aPathName
  5020     "the actual code to return the fileNumber (i.e. inode number) of a file."
  5073     "the actual code to return the fileNumber (i.e. inode number) of a file."
  5021 
  5074 
       
  5075     |encodedPathName|
       
  5076 
       
  5077     encodedPathName := self encodePath:aPathName.
  5022 %{
  5078 %{
  5023     struct stat buf;
  5079     struct stat buf;
  5024     int ret;
  5080     int ret;
  5025     unsigned INT ino;
  5081     unsigned INT ino;
  5026     OBJ retVal;
  5082     OBJ retVal;
  5027 
  5083 
  5028     if (__isStringLike(aPathName)) {
  5084     if (__isStringLike(encodedPathName)) {
  5029 # ifdef TRACE_STAT_CALLS
  5085 # ifdef TRACE_STAT_CALLS
  5030 	printf("stat on '%s' for id\n", __stringVal(aPathName));
  5086         printf("stat on '%s' for id\n", __stringVal(encodedPathName));
  5031 # endif
  5087 # endif
  5032 	__BEGIN_INTERRUPTABLE__
  5088         __BEGIN_INTERRUPTABLE__
  5033 	do {
  5089         do {
  5034 	    ret = stat((char *) __stringVal(aPathName), &buf);
  5090             ret = stat((char *) __stringVal(encodedPathName), &buf);
  5035 	} while (ret < 0 && errno == EINTR);
  5091         } while (ret < 0 && errno == EINTR);
  5036 	__END_INTERRUPTABLE__
  5092         __END_INTERRUPTABLE__
  5037 	if (ret >= 0) {
  5093         if (ret >= 0) {
  5038 	    ino = buf.st_ino;
  5094             ino = buf.st_ino;
  5039 	    retVal = __MKUINT(ino);
  5095             retVal = __MKUINT(ino);
  5040 	    RETURN (retVal);
  5096             RETURN (retVal);
  5041 	}
  5097         }
  5042 	@global(LastErrorNumber) = __mkSmallInteger(errno);
  5098         @global(LastErrorNumber) = __mkSmallInteger(errno);
  5043 	RETURN (nil);
  5099         RETURN (nil);
  5044     }
  5100     }
  5045     RETURN (nil);
  5101     RETURN (nil);
  5046 %}.
  5102 %}.
  5047 !
  5103 !
  5048 
  5104 
  5060      This method here returns nil, if the OS does not provide a
  5116      This method here returns nil, if the OS does not provide a
  5061      realPath library function.
  5117      realPath library function.
  5062      Notice: if symbolic links are involved, the result may look different
  5118      Notice: if symbolic links are involved, the result may look different
  5063      from what you expect."
  5119      from what you expect."
  5064 
  5120 
  5065     |path|
       
  5066 
       
  5067 %{  /* UNLIMITEDSTACK */
  5121 %{  /* UNLIMITEDSTACK */
  5068 
  5122 
  5069     if (__isStringLike(pathName)) {
  5123     if (__isStringLike(pathName)) {
  5070         if (strcmp(__stringVal(pathName), ".") == 0) {
       
  5071             char nameBuffer[MAXPATHLEN + 1];
       
  5072 
       
  5073             if (@global(CurrentDirectory) == nil) {
       
  5074                 if (getcwd(nameBuffer, MAXPATHLEN)) {
       
  5075                     OBJ d;
       
  5076 
       
  5077                     @global(CurrentDirectory) = d = __MKSTRING(nameBuffer);
       
  5078                     __GSTORE(d);
       
  5079                 }
       
  5080             }
       
  5081             RETURN (@global(CurrentDirectory));
       
  5082         }
       
  5083 
       
  5084 #ifdef HAS_REALPATH
  5124 #ifdef HAS_REALPATH
  5085         {
  5125         {
  5086             char nameBuffer[MAXPATHLEN+1];
  5126             char nameBuffer[MAXPATHLEN+1];
  5087 
  5127 
  5088             if (realpath(__stringVal(pathName), nameBuffer)) {
  5128             if (realpath(__stringVal(pathName), nameBuffer)) {
  5089                 RETURN ( __MKSTRING(nameBuffer) );
  5129                 RETURN ( __MKSTRING(nameBuffer) );
  5090             }
  5130             }
  5091             RETURN ( nil );
       
  5092         }
  5131         }
  5093 #endif /* ! HAS_REALPATH */
  5132 #endif /* ! HAS_REALPATH */
  5094     }
  5133     }
  5095 %}.
  5134 %}.
  5096     ^ nil
  5135     ^ nil
  5099 timeOfLastAccess:aPathName
  5138 timeOfLastAccess:aPathName
  5100     "return the time, when the file was last accessed.
  5139     "return the time, when the file was last accessed.
  5101      For nonexistent files, nil is returned."
  5140      For nonexistent files, nil is returned."
  5102 
  5141 
  5103     "could be implemented as:
  5142     "could be implemented as:
  5104 	(self infoOf:aPathName) accessed
  5143         (self infoOf:aPathName) accessed
  5105     "
  5144     "
  5106     |osSeconds i|
  5145     |osSeconds i encodedPathName|
       
  5146 
       
  5147     encodedPathName := self encodePath:aPathName.
       
  5148 
  5107 %{
  5149 %{
  5108     struct stat buf;
  5150     struct stat buf;
  5109     time_t mtime;
  5151     time_t mtime;
  5110     int ret;
  5152     int ret;
  5111 
  5153 
  5112     if (__isStringLike(aPathName)) {
  5154     if (__isStringLike(encodedPathName)) {
  5113 # ifdef TRACE_STAT_CALLS
  5155 # ifdef TRACE_STAT_CALLS
  5114 	printf("stat on '%s' for timeOfLastAccess\n", __stringVal(aPathName));
  5156         printf("stat on '%s' for timeOfLastAccess\n", __stringVal(encodedPathName));
  5115 # endif
  5157 # endif
  5116 	__BEGIN_INTERRUPTABLE__
  5158         __BEGIN_INTERRUPTABLE__
  5117 	do {
  5159         do {
  5118 	    ret = stat((char *) __stringVal(aPathName), &buf);
  5160             ret = stat((char *) __stringVal(encodedPathName), &buf);
  5119 	} while (ret < 0 && errno == EINTR);
  5161         } while (ret < 0 && errno == EINTR);
  5120 	__END_INTERRUPTABLE__
  5162         __END_INTERRUPTABLE__
  5121 	if (ret < 0) {
  5163         if (ret < 0) {
  5122 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  5164             @global(LastErrorNumber) = __mkSmallInteger(errno);
  5123 	    RETURN (nil);
  5165             RETURN (nil);
  5124 	}
  5166         }
  5125 	osSeconds = __MKUINT(buf.st_atime);
  5167         osSeconds = __MKUINT(buf.st_atime);
  5126     }
  5168     }
  5127 %}.
  5169 %}.
  5128     osSeconds notNil ifTrue:[^ Timestamp fromOSTime:(osSeconds * 1000)].
  5170     osSeconds notNil ifTrue:[^ Timestamp fromOSTime:(osSeconds * 1000)].
  5129 
  5171 
  5130     i := self infoOf:aPathName.
  5172     i := self infoOf:aPathName.
  5139 timeOfLastChange:aPathName
  5181 timeOfLastChange:aPathName
  5140     "return the time, when the file was last changed.
  5182     "return the time, when the file was last changed.
  5141      For nonexistent files, nil is returned."
  5183      For nonexistent files, nil is returned."
  5142 
  5184 
  5143     "could be implemented as:
  5185     "could be implemented as:
  5144 	(self infoOf:aPathName) modified
  5186         (self infoOf:aPathName) modified
  5145     "
  5187     "
  5146 
  5188 
  5147     |osSeconds i|
  5189     |osSeconds i encodedPathName|
       
  5190 
       
  5191     encodedPathName := self encodePath:aPathName.
  5148 %{
  5192 %{
  5149     struct stat buf;
  5193     struct stat buf;
  5150     int ret;
  5194     int ret;
  5151     time_t mtime;
  5195     time_t mtime;
  5152 
  5196 
  5153     if (__isStringLike(aPathName)) {
  5197     if (__isStringLike(encodedPathName)) {
  5154 # ifdef TRACE_STAT_CALLS
  5198 # ifdef TRACE_STAT_CALLS
  5155 	printf("stat on '%s' for timeOfLastChange\n", __stringVal(aPathName));
  5199         printf("stat on '%s' for timeOfLastChange\n", __stringVal(encodedPathName));
  5156 # endif
  5200 # endif
  5157 	__BEGIN_INTERRUPTABLE__
  5201         __BEGIN_INTERRUPTABLE__
  5158 	do {
  5202         do {
  5159 	    ret = stat((char *) __stringVal(aPathName), &buf);
  5203             ret = stat((char *) __stringVal(encodedPathName), &buf);
  5160 	} while (ret < 0 && errno == EINTR);
  5204         } while (ret < 0 && errno == EINTR);
  5161 	__END_INTERRUPTABLE__
  5205         __END_INTERRUPTABLE__
  5162 	if (ret < 0) {
  5206         if (ret < 0) {
  5163 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  5207             @global(LastErrorNumber) = __mkSmallInteger(errno);
  5164 	    RETURN ( nil );
  5208             RETURN ( nil );
  5165 	}
  5209         }
  5166 	osSeconds = __MKUINT(buf.st_mtime);
  5210         osSeconds = __MKUINT(buf.st_mtime);
  5167     }
  5211     }
  5168 %}.
  5212 %}.
  5169     osSeconds notNil ifTrue:[^ Timestamp fromOSTime:(osSeconds * 1000)].
  5213     osSeconds notNil ifTrue:[^ Timestamp fromOSTime:(osSeconds * 1000)].
  5170 
  5214 
  5171     i := self infoOf:aPathName.
  5215     i := self infoOf:aPathName.
  5180 typeOf:aPathName
  5224 typeOf:aPathName
  5181     "return the type of a file as a symbol; for nonexistent files,
  5225     "return the type of a file as a symbol; for nonexistent files,
  5182      nil is returned.
  5226      nil is returned.
  5183      Notice: for symbolic links, the type of the pointed-to file is returned."
  5227      Notice: for symbolic links, the type of the pointed-to file is returned."
  5184 
  5228 
  5185     |i|
  5229     |i osSeconds encodedPathName|
       
  5230 
       
  5231     encodedPathName := self encodePath:aPathName.
  5186 
  5232 
  5187     "
  5233     "
  5188      this could have been implemented as:
  5234      this could have been implemented as:
  5189 	(self infoOf:aPathName) type
  5235         (self infoOf:aPathName) type
  5190      but for huge directory searches the code below is faster
  5236      but for huge directory searches the code below is faster
  5191     "
  5237     "
  5192 
  5238 
  5193 %{
  5239 %{
  5194     struct stat buf;
  5240     struct stat buf;
  5195     int ret;
  5241     int ret;
  5196 
  5242 
  5197     if (__isStringLike(aPathName)) {
  5243     if (__isStringLike(encodedPathName)) {
  5198 # ifdef TRACE_STAT_CALLS
  5244 # ifdef TRACE_STAT_CALLS
  5199 	printf("stat on '%s' for type\n", __stringVal(aPathName));
  5245         printf("stat on '%s' for type\n", __stringVal(encodedPathName));
  5200 # endif
  5246 # endif
  5201 	__BEGIN_INTERRUPTABLE__
  5247         __BEGIN_INTERRUPTABLE__
  5202 	do {
  5248         do {
  5203 	    ret = stat((char *) __stringVal(aPathName), &buf);
  5249             ret = stat((char *) __stringVal(encodedPathName), &buf);
  5204 	} while (ret < 0 && errno == EINTR);
  5250         } while (ret < 0 && errno == EINTR);
  5205 	__END_INTERRUPTABLE__
  5251         __END_INTERRUPTABLE__
  5206 	if (ret < 0) {
  5252         if (ret < 0) {
  5207 	    @global(LastErrorNumber) = __mkSmallInteger(errno);
  5253             @global(LastErrorNumber) = __mkSmallInteger(errno);
  5208 	    RETURN ( nil );
  5254             RETURN ( nil );
  5209 	}
  5255         }
  5210 	switch (buf.st_mode & S_IFMT) {
  5256         switch (buf.st_mode & S_IFMT) {
  5211 	    case S_IFDIR:
  5257             case S_IFDIR:
  5212 		RETURN ( @symbol(directory) );
  5258                 RETURN ( @symbol(directory) );
  5213 	    case S_IFREG:
  5259             case S_IFREG:
  5214 		RETURN ( @symbol(regular) );
  5260                 RETURN ( @symbol(regular) );
  5215 # ifdef S_IFCHR
  5261 # ifdef S_IFCHR
  5216 	    case S_IFCHR:
  5262             case S_IFCHR:
  5217 		RETURN ( @symbol(characterSpecial) );
  5263                 RETURN ( @symbol(characterSpecial) );
  5218 # endif
  5264 # endif
  5219 # ifdef S_IFBLK
  5265 # ifdef S_IFBLK
  5220 	    case S_IFBLK:
  5266             case S_IFBLK:
  5221 		RETURN ( @symbol(blockSpecial) );
  5267                 RETURN ( @symbol(blockSpecial) );
  5222 # endif
  5268 # endif
  5223 # ifdef S_IFLNK
  5269 # ifdef S_IFLNK
  5224 	    case S_IFLNK:
  5270             case S_IFLNK:
  5225 		RETURN ( @symbol(symbolicLink) );
  5271                 RETURN ( @symbol(symbolicLink) );
  5226 # endif
  5272 # endif
  5227 # ifdef S_IFSOCK
  5273 # ifdef S_IFSOCK
  5228 	    case S_IFSOCK:
  5274             case S_IFSOCK:
  5229 		RETURN ( @symbol(socket) );
  5275                 RETURN ( @symbol(socket) );
  5230 # endif
  5276 # endif
  5231 # ifdef S_IFIFO
  5277 # ifdef S_IFIFO
  5232 	    case S_IFIFO:
  5278             case S_IFIFO:
  5233 		RETURN ( @symbol(fifo) );
  5279                 RETURN ( @symbol(fifo) );
  5234 # endif
  5280 # endif
  5235 	    default:
  5281             default:
  5236 		RETURN ( @symbol(unknown) );
  5282                 RETURN ( @symbol(unknown) );
  5237 	}
  5283         }
  5238     }
  5284     }
  5239 %}.
  5285 %}.
  5240     i := self infoOf:aPathName.
  5286     i := self infoOf:aPathName.
  5241     i notNil ifTrue:[^ i type].
  5287     i notNil ifTrue:[^ i type].
  5242     ^ nil.
  5288     ^ nil.
  8377 
  8423 
  8378 ! !
  8424 ! !
  8379 
  8425 
  8380 !UnixOperatingSystem class methodsFor:'path queries'!
  8426 !UnixOperatingSystem class methodsFor:'path queries'!
  8381 
  8427 
       
  8428 decodePath:encodedPathName 
       
  8429     "decode the pathName as returned by system calls.
       
  8430      E.g. linux system calls return sigle byte strings only,
       
  8431      so the pathName has been UTF-8 decoded."
       
  8432     
       
  8433     "linux strings are in UTF8 (in contemporary linux versions)"
       
  8434     encodedPathName notNil ifTrue:[
       
  8435         [
       
  8436             ^ encodedPathName utf8Decoded.
       
  8437         ] on:InvalidEncodingError do:[:ex|
       
  8438             "maybe there are old filenames in ISO8859-x,
       
  8439              just keep them untranslated"
       
  8440         ].
       
  8441     ].
       
  8442     ^ encodedPathName
       
  8443 !
       
  8444 
  8382 defaultSystemPath
  8445 defaultSystemPath
  8383     "add additional directories to the systemPath
  8446     "add additional directories to the systemPath
  8384      (but only, if the major version is the same)"
  8447      (but only, if the major version is the same)"
  8385 
  8448 
  8386     |sysPath majorVersionNr releaseFile s v|
  8449     |sysPath majorVersionNr releaseFile s v|
  8425     ^ sysPath
  8488     ^ sysPath
  8426 
  8489 
  8427     "
  8490     "
  8428      OperatingSystem defaultSystemPath
  8491      OperatingSystem defaultSystemPath
  8429     "
  8492     "
       
  8493 !
       
  8494 
       
  8495 encodePath:pathName 
       
  8496     "encode the pathName for use with system calls.
       
  8497      E.g. linux system calls accept sigle byte strings only,
       
  8498      so the pathName has been UTF-8 encoded, before using it in a system call."
       
  8499     
       
  8500     ^ pathName utf8Encoded
  8430 ! !
  8501 ! !
  8431 
  8502 
  8432 !UnixOperatingSystem class methodsFor:'private'!
  8503 !UnixOperatingSystem class methodsFor:'private'!
  8433 
  8504 
  8434 mountPointsFromProcFS
  8505 mountPointsFromProcFS
 13290 ! !
 13361 ! !
 13291 
 13362 
 13292 !UnixOperatingSystem class methodsFor:'documentation'!
 13363 !UnixOperatingSystem class methodsFor:'documentation'!
 13293 
 13364 
 13294 version
 13365 version
 13295     ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.289 2012-12-13 11:13:51 stefan Exp $'
 13366     ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.290 2012-12-13 13:20:12 stefan Exp $'
 13296 !
 13367 !
 13297 
 13368 
 13298 version_CVS
 13369 version_CVS
 13299     ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.289 2012-12-13 11:13:51 stefan Exp $'
 13370     ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.290 2012-12-13 13:20:12 stefan Exp $'
 13300 ! !
 13371 ! !
 13301 
 13372 
 13302 UnixOperatingSystem initialize!
 13373 UnixOperatingSystem initialize!
 13303 UnixOperatingSystem::FileDescriptorHandle initialize!
 13374 UnixOperatingSystem::FileDescriptorHandle initialize!