#include "tclInt.h"
#include "tclMac.h"
#include "tclMacInt.h"
#include "tclPort.h"
#include <FSpCompat.h>
#include <MoreFilesExtras.h>
#include <Strings.h>
#include <Errors.h>
#include <FileCopy.h>
#include <DirectoryCopy.h>
#include <Script.h>
#include <string.h>
#include <Finder.h>
#include <Aliases.h>
static int GetFileFinderAttributes _ANSI_ARGS_((Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj **attributePtrPtr));
static int GetFileReadOnly _ANSI_ARGS_((Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj **readOnlyPtrPtr));
static int SetFileFinderAttributes _ANSI_ARGS_((Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj *attributePtr));
static int SetFileReadOnly _ANSI_ARGS_((Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj *readOnlyPtr));
#define MAC_CREATOR_ATTRIBUTE 0
#define MAC_HIDDEN_ATTRIBUTE 1
#define MAC_READONLY_ATTRIBUTE 2
#define MAC_TYPE_ATTRIBUTE 3
CONST char *tclpFileAttrStrings[] = {"-creator", "-hidden", "-readonly",
"-type", (char *) NULL};
CONST TclFileAttrProcs tclpFileAttrProcs[] = {
{GetFileFinderAttributes, SetFileFinderAttributes},
{GetFileFinderAttributes, SetFileFinderAttributes},
{GetFileReadOnly, SetFileReadOnly},
{GetFileFinderAttributes, SetFileFinderAttributes}};
static long startSeed = 248923489;
static pascal Boolean CopyErrHandler _ANSI_ARGS_((OSErr error,
short failedOperation,
short srcVRefNum, long srcDirID,
ConstStr255Param srcName, short dstVRefNum,
long dstDirID,ConstStr255Param dstName));
static int DoCopyDirectory _ANSI_ARGS_((CONST char *src,
CONST char *dst, Tcl_DString *errorPtr));
static int DoCopyFile _ANSI_ARGS_((CONST char *src,
CONST char *dst));
static int DoCreateDirectory _ANSI_ARGS_((CONST char *path));
static int DoDeleteFile _ANSI_ARGS_((CONST char *path));
static int DoRemoveDirectory _ANSI_ARGS_((CONST char *path,
int recursive, Tcl_DString *errorPtr));
static int DoRenameFile _ANSI_ARGS_((CONST char *src,
CONST char *dst));
OSErr FSpGetFLockCompat _ANSI_ARGS_((const FSSpec *specPtr,
Boolean *lockedPtr));
static OSErr GetFileSpecs _ANSI_ARGS_((CONST char *path,
FSSpec *pathSpecPtr, FSSpec *dirSpecPtr,
Boolean *pathExistsPtr,
Boolean *pathIsDirectoryPtr));
static OSErr MoveRename _ANSI_ARGS_((const FSSpec *srcSpecPtr,
const FSSpec *dstSpecPtr, StringPtr copyName));
static int Pstrequal _ANSI_ARGS_((ConstStr255Param stringA,
ConstStr255Param stringB));
int
TclpObjRenameFile(srcPathPtr, destPathPtr)
Tcl_Obj *srcPathPtr;
Tcl_Obj *destPathPtr;
{
return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr),
Tcl_FSGetNativePath(destPathPtr));
}
static int
DoRenameFile(
CONST char *src,
CONST char *dst)
{
FSSpec srcFileSpec, dstFileSpec, dstDirSpec;
OSErr err;
long srcID, dummy;
Boolean srcIsDirectory, dstIsDirectory, dstExists, dstLocked;
err = FSpLLocationFromPath(strlen(src), src, &srcFileSpec);
if (err == noErr) {
FSpGetDirectoryID(&srcFileSpec, &srcID, &srcIsDirectory);
}
if (err == noErr) {
err = GetFileSpecs(dst, &dstFileSpec, &dstDirSpec, &dstExists,
&dstIsDirectory);
}
if (err == noErr) {
if (dstExists == 0) {
err = MoveRename(&srcFileSpec, &dstDirSpec, dstFileSpec.name);
goto end;
}
err = FSpGetFLockCompat(&dstFileSpec, &dstLocked);
if (dstLocked) {
FSpRstFLockCompat(&dstFileSpec);
}
}
if (err == noErr) {
if (srcIsDirectory) {
if (dstIsDirectory) {
if (DoRemoveDirectory(dst, 0, NULL) != TCL_OK) {
return TCL_ERROR;
}
err = MoveRename(&srcFileSpec, &dstDirSpec, dstFileSpec.name);
if (err != noErr) {
FSpDirCreateCompat(&dstFileSpec, smSystemScript, &dummy);
if (dstLocked) {
FSpSetFLockCompat(&dstFileSpec);
}
}
} else {
errno = ENOTDIR;
return TCL_ERROR;
}
} else {
if (dstIsDirectory) {
errno = EISDIR;
return TCL_ERROR;
} else {
Str31 tmpName;
FSSpec tmpFileSpec;
err = GenerateUniqueName(dstFileSpec.vRefNum, &startSeed,
dstFileSpec.parID, dstFileSpec.parID, tmpName);
if (err == noErr) {
err = FSpRenameCompat(&dstFileSpec, tmpName);
}
if (err == noErr) {
err = FSMakeFSSpecCompat(dstFileSpec.vRefNum,
dstFileSpec.parID, tmpName, &tmpFileSpec);
}
if (err == noErr) {
err = MoveRename(&srcFileSpec, &dstDirSpec,
dstFileSpec.name);
}
if (err == noErr) {
FSpDeleteCompat(&tmpFileSpec);
} else {
FSpDeleteCompat(&dstFileSpec);
FSpRenameCompat(&tmpFileSpec, dstFileSpec.name);
if (dstLocked) {
FSpSetFLockCompat(&dstFileSpec);
}
}
}
}
}
end:
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return TCL_ERROR;
}
return TCL_OK;
}
static OSErr
MoveRename(
const FSSpec *srcFileSpecPtr,
const FSSpec *dstDirSpecPtr,
StringPtr copyName)
{
OSErr err;
long srcID, dstID;
Boolean srcIsDir, dstIsDir;
Str31 tmpName;
FSSpec dstFileSpec, srcDirSpec, tmpSrcFileSpec, tmpDstFileSpec;
Boolean locked;
if (srcFileSpecPtr->parID == 1) {
return badMovErr;
}
if (srcFileSpecPtr->vRefNum != dstDirSpecPtr->vRefNum) {
return diffVolErr;
}
err = FSpGetFLockCompat(srcFileSpecPtr, &locked);
if (locked) {
FSpRstFLockCompat(srcFileSpecPtr);
}
if (err == noErr) {
err = FSpGetDirectoryID(dstDirSpecPtr, &dstID, &dstIsDir);
}
if (err == noErr) {
if (srcFileSpecPtr->parID == dstID) {
err = FSpRenameCompat(srcFileSpecPtr, copyName);
goto done;
}
if (Pstrequal(srcFileSpecPtr->name, copyName)) {
err = FSpCatMoveCompat(srcFileSpecPtr, dstDirSpecPtr);
goto done;
}
err = FSpGetDirectoryID(srcFileSpecPtr, &srcID, &srcIsDir);
}
if (err == noErr) {
err = GenerateUniqueName(srcFileSpecPtr->vRefNum, &startSeed,
srcFileSpecPtr->parID, dstID, tmpName);
FSMakeFSSpecCompat(srcFileSpecPtr->vRefNum, srcFileSpecPtr->parID,
tmpName, &tmpSrcFileSpec);
FSMakeFSSpecCompat(dstDirSpecPtr->vRefNum, dstID, tmpName,
&tmpDstFileSpec);
}
if (err == noErr) {
err = FSpRenameCompat(srcFileSpecPtr, tmpName);
}
if (err == noErr) {
err = FSpCatMoveCompat(&tmpSrcFileSpec, dstDirSpecPtr);
if (err == noErr) {
err = FSpRenameCompat(&tmpDstFileSpec, copyName);
if (err == noErr) {
goto done;
}
FSMakeFSSpecCompat(srcFileSpecPtr->vRefNum, srcFileSpecPtr->parID,
NULL, &srcDirSpec);
FSpCatMoveCompat(&tmpDstFileSpec, &srcDirSpec);
}
FSpRenameCompat(&tmpSrcFileSpec, srcFileSpecPtr->name);
}
done:
if (locked != false) {
if (err == noErr) {
FSMakeFSSpecCompat(dstDirSpecPtr->vRefNum,
dstID, copyName, &dstFileSpec);
FSpSetFLockCompat(&dstFileSpec);
} else {
FSpSetFLockCompat(srcFileSpecPtr);
}
}
return err;
}
int
TclpObjCopyFile(srcPathPtr, destPathPtr)
Tcl_Obj *srcPathPtr;
Tcl_Obj *destPathPtr;
{
return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr),
Tcl_FSGetNativePath(destPathPtr));
}
static int
DoCopyFile(
CONST char *src,
CONST char *dst)
{
OSErr err, dstErr;
Boolean dstExists, dstIsDirectory, dstLocked;
FSSpec srcFileSpec, dstFileSpec, dstDirSpec, tmpFileSpec;
Str31 tmpName;
err = FSpLLocationFromPath(strlen(src), src, &srcFileSpec);
if (err == noErr) {
err = GetFileSpecs(dst, &dstFileSpec, &dstDirSpec, &dstExists,
&dstIsDirectory);
}
if (dstExists) {
if (dstIsDirectory) {
errno = EISDIR;
return TCL_ERROR;
}
err = FSpGetFLockCompat(&dstFileSpec, &dstLocked);
if (dstLocked) {
FSpRstFLockCompat(&dstFileSpec);
}
dstErr = GenerateUniqueName(dstFileSpec.vRefNum, &startSeed, dstFileSpec.parID,
dstFileSpec.parID, tmpName);
if (dstErr == noErr) {
dstErr = FSpRenameCompat(&dstFileSpec, tmpName);
}
}
if (err == noErr) {
err = FSpFileCopy(&srcFileSpec, &dstDirSpec,
(StringPtr) dstFileSpec.name, NULL, 0, true);
}
if ((dstExists != false) && (dstErr == noErr)) {
FSMakeFSSpecCompat(dstFileSpec.vRefNum, dstFileSpec.parID,
tmpName, &tmpFileSpec);
if (err == noErr) {
FSpDeleteCompat(&tmpFileSpec);
} else {
FSpDeleteCompat(&dstFileSpec);
FSpRenameCompat(&tmpFileSpec, dstFileSpec.name);
if (dstLocked) {
FSpSetFLockCompat(&dstFileSpec);
}
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return TCL_ERROR;
}
return TCL_OK;
}
int
TclpObjDeleteFile(pathPtr)
Tcl_Obj *pathPtr;
{
return DoDeleteFile(Tcl_FSGetNativePath(pathPtr));
}
static int
DoDeleteFile(
CONST char *path)
{
OSErr err;
FSSpec fileSpec;
Boolean isDirectory;
long dirID;
err = FSpLLocationFromPath(strlen(path), path, &fileSpec);
if (err == noErr) {
FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
if (isDirectory == true) {
errno = EISDIR;
return TCL_ERROR;
}
}
err = FSpDeleteCompat(&fileSpec);
if (err == fLckdErr) {
FSpRstFLockCompat(&fileSpec);
err = FSpDeleteCompat(&fileSpec);
if (err != noErr) {
FSpSetFLockCompat(&fileSpec);
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return TCL_ERROR;
}
return TCL_OK;
}
int
TclpObjCreateDirectory(pathPtr)
Tcl_Obj *pathPtr;
{
return DoCreateDirectory(Tcl_FSGetNativePath(pathPtr));
}
static int
DoCreateDirectory(
CONST char *path)
{
OSErr err;
FSSpec dirSpec;
long outDirID;
err = FSpLocationFromPath(strlen(path), path, &dirSpec);
if (err == noErr) {
err = dupFNErr;
} else if (err == fnfErr) {
err = FSpDirCreateCompat(&dirSpec, smSystemScript, &outDirID);
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return TCL_ERROR;
}
return TCL_OK;
}
int
TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
Tcl_Obj *srcPathPtr;
Tcl_Obj *destPathPtr;
Tcl_Obj **errorPtr;
{
Tcl_DString ds;
int ret;
ret = DoCopyDirectory(Tcl_FSGetNativePath(srcPathPtr),
Tcl_FSGetNativePath(destPathPtr), &ds);
if (ret != TCL_OK) {
*errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
Tcl_DStringFree(&ds);
Tcl_IncrRefCount(*errorPtr);
}
return ret;
}
static int
DoCopyDirectory(
CONST char *src,
CONST char *dst,
Tcl_DString *errorPtr)
{
OSErr err, saveErr;
long srcID, tmpDirID;
FSSpec srcFileSpec, dstFileSpec, dstDirSpec, tmpDirSpec, tmpFileSpec;
Boolean srcIsDirectory, srcLocked;
Boolean dstIsDirectory, dstExists;
Str31 tmpName;
err = FSpLocationFromPath(strlen(src), src, &srcFileSpec);
if (err == noErr) {
err = FSpGetDirectoryID(&srcFileSpec, &srcID, &srcIsDirectory);
}
if (err == noErr) {
if (srcIsDirectory == false) {
err = afpObjectTypeErr;
}
}
if (err == noErr) {
err = GetFileSpecs(dst, &dstFileSpec, &dstDirSpec, &dstExists,
&dstIsDirectory);
}
if (dstExists) {
if (dstIsDirectory == false) {
err = afpObjectTypeErr;
} else {
err = dupFNErr;
}
}
if (err != noErr) {
goto done;
}
if ((srcFileSpec.vRefNum == dstFileSpec.vRefNum) &&
(srcFileSpec.parID == dstFileSpec.parID) &&
(Pstrequal(srcFileSpec.name, dstFileSpec.name) != 0)) {
goto done;
}
err = FSpGetFLockCompat(&srcFileSpec, &srcLocked);
if (srcLocked) {
FSpRstFLockCompat(&srcFileSpec);
}
if (err == noErr) {
err = GenerateUniqueName(dstFileSpec.vRefNum, &startSeed, dstFileSpec.parID,
dstFileSpec.parID, tmpName);
}
if (err == noErr) {
FSMakeFSSpecCompat(dstFileSpec.vRefNum, dstFileSpec.parID,
tmpName, &tmpDirSpec);
err = FSpDirCreateCompat(&tmpDirSpec, smSystemScript, &tmpDirID);
}
if (err == noErr) {
err = FSpDirectoryCopy(&srcFileSpec, &tmpDirSpec, NULL, NULL, 0, true,
CopyErrHandler);
}
saveErr = err;
err = noErr;
if (Pstrequal(srcFileSpec.name, dstFileSpec.name) == 0) {
err = FSMakeFSSpecCompat(tmpDirSpec.vRefNum, tmpDirID,
srcFileSpec.name, &tmpFileSpec);
if (err == noErr) {
err = FSpRenameCompat(&tmpFileSpec, dstFileSpec.name);
}
}
if (err == noErr) {
err = FSMakeFSSpecCompat(tmpDirSpec.vRefNum, tmpDirID,
dstFileSpec.name, &tmpFileSpec);
}
if (err == noErr) {
err = FSpCatMoveCompat(&tmpFileSpec, &dstDirSpec);
}
if (err == noErr) {
if (srcLocked) {
FSpSetFLockCompat(&dstFileSpec);
}
}
FSpDeleteCompat(&tmpDirSpec);
if (saveErr != noErr) {
err = saveErr;
}
done:
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
if (errorPtr != NULL) {
Tcl_ExternalToUtfDString(NULL, dst, -1, errorPtr);
}
return TCL_ERROR;
}
return TCL_OK;
}
static pascal Boolean
CopyErrHandler(
OSErr error,
short failedOperation,
short srcVRefNum,
long srcDirID,
ConstStr255Param srcName,
short dstVRefNum,
long dstDirID,
ConstStr255Param dstName)
{
return true;
}
int
TclpObjRemoveDirectory(pathPtr, recursive, errorPtr)
Tcl_Obj *pathPtr;
int recursive;
Tcl_Obj **errorPtr;
{
Tcl_DString ds;
int ret;
ret = DoRemoveDirectory(Tcl_FSGetNativePath(pathPtr),recursive, &ds);
if (ret != TCL_OK) {
*errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
Tcl_DStringFree(&ds);
Tcl_IncrRefCount(*errorPtr);
}
return ret;
}
static int
DoRemoveDirectory(
CONST char *path,
int recursive,
Tcl_DString *errorPtr)
{
OSErr err;
FSSpec fileSpec;
long dirID;
int locked;
Boolean isDirectory;
CInfoPBRec pb;
Str255 fileName;
locked = 0;
err = FSpLocationFromPath(strlen(path), path, &fileSpec);
if (err != noErr) {
goto done;
}
isDirectory = 1;
FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
if (isDirectory == 0) {
errno = ENOTDIR;
return TCL_ERROR;
}
err = FSpDeleteCompat(&fileSpec);
if (err == fLckdErr) {
locked = 1;
FSpRstFLockCompat(&fileSpec);
err = FSpDeleteCompat(&fileSpec);
}
if (err == noErr) {
return TCL_OK;
}
if (err != fBsyErr) {
goto done;
}
if (recursive == 0) {
pb.hFileInfo.ioVRefNum = fileSpec.vRefNum;
pb.hFileInfo.ioDirID = dirID;
pb.hFileInfo.ioNamePtr = (StringPtr) fileName;
pb.hFileInfo.ioFDirIndex = 1;
if (PBGetCatInfoSync(&pb) == noErr) {
err = dupFNErr;
goto done;
}
}
err = DeleteDirectory(fileSpec.vRefNum, dirID, NULL);
done:
if (err != noErr) {
if (errorPtr != NULL) {
Tcl_UtfToExternalDString(NULL, path, -1, errorPtr);
}
if (locked) {
FSpSetFLockCompat(&fileSpec);
}
errno = TclMacOSErrorToPosixError(err);
return TCL_ERROR;
}
return TCL_OK;
}
static OSErr
GetFileSpecs(
CONST char *path,
FSSpec *pathSpecPtr,
FSSpec *dirSpecPtr,
Boolean *pathExistsPtr,
Boolean *pathIsDirectoryPtr)
{
CONST char *dirName;
OSErr err;
int argc;
CONST char **argv;
long d;
Tcl_DString buffer;
*pathExistsPtr = false;
*pathIsDirectoryPtr = false;
Tcl_DStringInit(&buffer);
Tcl_SplitPath(path, &argc, &argv);
if (argc == 1) {
dirName = ":";
} else {
dirName = Tcl_JoinPath(argc - 1, argv, &buffer);
}
err = FSpLocationFromPath(strlen(dirName), dirName, dirSpecPtr);
Tcl_DStringFree(&buffer);
ckfree((char *) argv);
if (err == noErr) {
err = FSpLocationFromPath(strlen(path), path, pathSpecPtr);
if (err == noErr) {
*pathExistsPtr = true;
err = FSpGetDirectoryID(pathSpecPtr, &d, pathIsDirectoryPtr);
} else if (err == fnfErr) {
err = noErr;
}
}
return err;
}
OSErr
FSpGetFLockCompat(
const FSSpec *specPtr,
Boolean *lockedPtr)
{
CInfoPBRec pb;
OSErr err;
pb.hFileInfo.ioVRefNum = specPtr->vRefNum;
pb.hFileInfo.ioDirID = specPtr->parID;
pb.hFileInfo.ioNamePtr = (StringPtr) specPtr->name;
pb.hFileInfo.ioFDirIndex = 0;
err = PBGetCatInfoSync(&pb);
if ((err == noErr) && (pb.hFileInfo.ioFlAttrib & 0x01)) {
*lockedPtr = true;
} else {
*lockedPtr = false;
}
return err;
}
static int
Pstrequal (
ConstStr255Param stringA,
ConstStr255Param stringB)
{
int i, len;
len = *stringA;
for (i = 0; i <= len; i++) {
if (*stringA++ != *stringB++) {
return 0;
}
}
return 1;
}
static int
GetFileFinderAttributes(
Tcl_Interp *interp,
int objIndex,
Tcl_Obj *fileName,
Tcl_Obj **attributePtrPtr)
{
OSErr err;
FSSpec fileSpec;
FInfo finfo;
CONST char *native;
native=Tcl_FSGetNativePath(fileName);
err = FSpLLocationFromPath(strlen(native),
native, &fileSpec);
if (err == noErr) {
err = FSpGetFInfo(&fileSpec, &finfo);
}
if (err == noErr) {
switch (objIndex) {
case MAC_CREATOR_ATTRIBUTE:
*attributePtrPtr = Tcl_NewOSTypeObj(finfo.fdCreator);
break;
case MAC_HIDDEN_ATTRIBUTE:
*attributePtrPtr = Tcl_NewBooleanObj(finfo.fdFlags
& kIsInvisible);
break;
case MAC_TYPE_ATTRIBUTE:
*attributePtrPtr = Tcl_NewOSTypeObj(finfo.fdType);
break;
}
} else if (err == fnfErr) {
long dirID;
Boolean isDirectory = 0;
err = FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
if ((err == noErr) && isDirectory) {
if (objIndex == MAC_HIDDEN_ATTRIBUTE) {
*attributePtrPtr = Tcl_NewBooleanObj(0);
} else {
*attributePtrPtr = Tcl_NewOSTypeObj('Fldr');
}
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"could not read \"", Tcl_GetString(fileName), "\": ",
Tcl_PosixError(interp), (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static int
GetFileReadOnly(
Tcl_Interp *interp,
int objIndex,
Tcl_Obj *fileName,
Tcl_Obj **readOnlyPtrPtr)
{
OSErr err;
FSSpec fileSpec;
CInfoPBRec paramBlock;
CONST char *native;
native=Tcl_FSGetNativePath(fileName);
err = FSpLLocationFromPath(strlen(native),
native, &fileSpec);
if (err == noErr) {
if (err == noErr) {
paramBlock.hFileInfo.ioCompletion = NULL;
paramBlock.hFileInfo.ioNamePtr = fileSpec.name;
paramBlock.hFileInfo.ioVRefNum = fileSpec.vRefNum;
paramBlock.hFileInfo.ioFDirIndex = 0;
paramBlock.hFileInfo.ioDirID = fileSpec.parID;
err = PBGetCatInfo(¶mBlock, 0);
if (err == noErr) {
*readOnlyPtrPtr = Tcl_NewBooleanObj(
paramBlock.hFileInfo.ioFlAttrib & 1);
}
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"could not read \"", Tcl_GetString(fileName), "\": ",
Tcl_PosixError(interp), (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static int
SetFileFinderAttributes(
Tcl_Interp *interp,
int objIndex,
Tcl_Obj *fileName,
Tcl_Obj *attributePtr)
{
OSErr err;
FSSpec fileSpec;
FInfo finfo;
CONST char *native;
native=Tcl_FSGetNativePath(fileName);
err = FSpLLocationFromPath(strlen(native),
native, &fileSpec);
if (err == noErr) {
err = FSpGetFInfo(&fileSpec, &finfo);
}
if (err == noErr) {
switch (objIndex) {
case MAC_CREATOR_ATTRIBUTE:
if (Tcl_GetOSTypeFromObj(interp, attributePtr,
&finfo.fdCreator) != TCL_OK) {
return TCL_ERROR;
}
break;
case MAC_HIDDEN_ATTRIBUTE: {
int hidden;
if (Tcl_GetBooleanFromObj(interp, attributePtr, &hidden)
!= TCL_OK) {
return TCL_ERROR;
}
if (hidden) {
finfo.fdFlags |= kIsInvisible;
} else {
finfo.fdFlags &= ~kIsInvisible;
}
break;
}
case MAC_TYPE_ATTRIBUTE:
if (Tcl_GetOSTypeFromObj(interp, attributePtr,
&finfo.fdType) != TCL_OK) {
return TCL_ERROR;
}
break;
}
err = FSpSetFInfo(&fileSpec, &finfo);
} else if (err == fnfErr) {
long dirID;
Boolean isDirectory = 0;
err = FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
if ((err == noErr) && isDirectory) {
Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
Tcl_AppendStringsToObj(resultPtr, "cannot set ",
tclpFileAttrStrings[objIndex], ": \"",
Tcl_GetString(fileName), "\" is a directory", (char *) NULL);
return TCL_ERROR;
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"could not read \"", Tcl_GetString(fileName), "\": ",
Tcl_PosixError(interp), (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static int
SetFileReadOnly(
Tcl_Interp *interp,
int objIndex,
Tcl_Obj *fileName,
Tcl_Obj *readOnlyPtr)
{
OSErr err;
FSSpec fileSpec;
HParamBlockRec paramBlock;
int hidden;
CONST char *native;
native=Tcl_FSGetNativePath(fileName);
err = FSpLLocationFromPath(strlen(native),
native, &fileSpec);
if (err == noErr) {
if (Tcl_GetBooleanFromObj(interp, readOnlyPtr, &hidden) != TCL_OK) {
return TCL_ERROR;
}
paramBlock.fileParam.ioCompletion = NULL;
paramBlock.fileParam.ioNamePtr = fileSpec.name;
paramBlock.fileParam.ioVRefNum = fileSpec.vRefNum;
paramBlock.fileParam.ioDirID = fileSpec.parID;
if (hidden) {
err = PBHSetFLock(¶mBlock, 0);
} else {
err = PBHRstFLock(¶mBlock, 0);
}
}
if (err == fnfErr) {
long dirID;
Boolean isDirectory = 0;
err = FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
if ((err == noErr) && isDirectory) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"cannot set a directory to read-only when File Sharing is turned off",
(char *) NULL);
return TCL_ERROR;
} else {
err = fnfErr;
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"could not read \"", Tcl_GetString(fileName), "\": ",
Tcl_PosixError(interp), (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
Tcl_Obj*
TclpObjListVolumes(void)
{
HParamBlockRec pb;
Str255 name;
OSErr theError = noErr;
Tcl_Obj *resultPtr, *elemPtr;
short volIndex = 1;
Tcl_DString dstr;
resultPtr = Tcl_NewObj();
while ( 1 ) {
pb.volumeParam.ioNamePtr = (StringPtr) &name;
pb.volumeParam.ioVolIndex = volIndex;
theError = PBHGetVInfoSync(&pb);
if ( theError != noErr ) {
break;
}
Tcl_ExternalToUtfDString(NULL, (CONST char *)&name[1], name[0], &dstr);
elemPtr = Tcl_NewStringObj(Tcl_DStringValue(&dstr),
Tcl_DStringLength(&dstr));
Tcl_AppendToObj(elemPtr, ":", 1);
Tcl_ListObjAppendElement(NULL, resultPtr, elemPtr);
Tcl_DStringFree(&dstr);
volIndex++;
}
Tcl_IncrRefCount(resultPtr);
return resultPtr;
}
int
TclpObjNormalizePath(interp, pathPtr, nextCheckpoint)
Tcl_Interp *interp;
Tcl_Obj *pathPtr;
int nextCheckpoint;
{
#define MAXMACFILENAMELEN 31
StrFileName fileName;
StringPtr fileNamePtr;
int fileNameLen,newPathLen;
Handle newPathHandle;
OSErr err;
short vRefNum;
long dirID;
Boolean isDirectory;
Boolean wasAlias=FALSE;
FSSpec fileSpec, lastFileSpec;
Tcl_DString nativeds;
char cur;
int firstCheckpoint=nextCheckpoint, lastCheckpoint;
int origPathLen;
char *path = Tcl_GetStringFromObj(pathPtr,&origPathLen);
{
int currDirValid=0;
while (1) {
cur = path[nextCheckpoint];
if (cur == ':' || cur == 0) {
if (cur == ':') {
nextCheckpoint++; cur = path[nextCheckpoint];
}
Tcl_UtfToExternalDString(NULL,path,nextCheckpoint,&nativeds);
err = FSpLLocationFromPath(Tcl_DStringLength(&nativeds),
Tcl_DStringValue(&nativeds),
&fileSpec);
Tcl_DStringFree(&nativeds);
if (err == noErr) {
lastFileSpec=fileSpec;
err = ResolveAliasFile(&fileSpec, true, &isDirectory,
&wasAlias);
if (err == noErr) {
err = FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
currDirValid = ((err == noErr) && isDirectory);
vRefNum = fileSpec.vRefNum;
}
}
break;
}
nextCheckpoint++;
}
if(!currDirValid) {
return firstCheckpoint;
}
}
lastCheckpoint=nextCheckpoint;
while (1) {
cur = path[nextCheckpoint];
if (cur == ':' || cur == 0) {
fileNameLen=nextCheckpoint-lastCheckpoint;
fileNamePtr=fileName;
if(fileNameLen==0) {
if (cur == ':') {
fileName[0]=2;
strcpy((char *) fileName + 1, "::");
lastCheckpoint--;
} else {
fileNamePtr=NULL;
}
} else {
Tcl_UtfToExternalDString(NULL,&path[lastCheckpoint],
fileNameLen,&nativeds);
fileNameLen=Tcl_DStringLength(&nativeds);
if(fileNameLen > MAXMACFILENAMELEN) {
err = bdNamErr;
} else {
fileName[0]=fileNameLen;
strncpy((char *) fileName + 1, Tcl_DStringValue(&nativeds),
fileNameLen);
}
Tcl_DStringFree(&nativeds);
}
if(err == noErr)
err=FSMakeFSSpecCompat(vRefNum, dirID, fileNamePtr, &fileSpec);
if(err != noErr) {
if(err != fnfErr) {
err=FSMakeFSSpecCompat(vRefNum, dirID, NULL, &fileSpec);
if(err != noErr) {
return firstCheckpoint;
}
nextCheckpoint=lastCheckpoint;
cur = path[lastCheckpoint];
}
break;
} else {
lastFileSpec=fileSpec;
err = ResolveAliasFile(&fileSpec, true, &isDirectory,
&wasAlias);
if (err != noErr || !isDirectory) {
break;
}
}
if (cur == 0) break;
err = FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
if (err != noErr || !isDirectory) {
break;
}
vRefNum = fileSpec.vRefNum;
lastCheckpoint=nextCheckpoint+1;
}
wasAlias=FALSE;
nextCheckpoint++;
}
if (wasAlias)
fileSpec=lastFileSpec;
err=FSpPathFromLocation(&fileSpec, &newPathLen, &newPathHandle);
if(err != noErr) {
return firstCheckpoint;
}
HLock(newPathHandle);
Tcl_ExternalToUtfDString(NULL,*newPathHandle,newPathLen,&nativeds);
if (cur != 0) {
if ( newPathLen==0 || (*(*newPathHandle+(newPathLen-1))!=':' && path[nextCheckpoint] !=':')) {
Tcl_DStringAppend(&nativeds, ":" , 1);
}
Tcl_DStringAppend(&nativeds, &path[nextCheckpoint],
strlen(&path[nextCheckpoint]));
}
DisposeHandle(newPathHandle);
fileNameLen=Tcl_DStringLength(&nativeds);
Tcl_SetStringObj(pathPtr,Tcl_DStringValue(&nativeds),fileNameLen);
Tcl_DStringFree(&nativeds);
return nextCheckpoint+(fileNameLen-origPathLen);
}