-- [h: ServerHandle, file: ROPE, str: IO.STREAM, created: GMT, proc: ConfirmProc] -- ~ {
{
ENABLE
UNWIND => {
IF dH # NIL THEN UnPinRemoteDirPath[dH];
IF rpcH # NIL THEN ReleaseRPCHandleAndConversation[h, rpcH, c];
IF buffer # NIL THEN RefText.ReleaseScratch[buffer];
};
tempNameOnServer, realBase: ROPE;
isPattern, createCaseFile: BOOL;
nR: NameReader;
createReply: SunNFS.DirOpRes;
reply: SunNFS.AttrStat;
offset: CARD;
version, specifiedVersion: Version;
vI: VersionInfo;
desiredMode: CARD;
nR ← CreateNameReader[file];
dH ← FollowDirPath[sH~h, nR~nR, case~FALSE, create~TRUE];
[base~realBase, vI~vI, version~specifiedVersion, isPattern~isPattern] ← ReadBaseComponent[nR~nR, case~FALSE, stripVersion~TRUE];
IF isPattern THEN ReportFSError[patternNotAllowed, h, file, "Create, pattern not allowed"];
SELECT vI
FROM
missing => ReportFSError[illegalName, h, file, "Create, version part required"];
bang => specifiedVersion ← FSBackdoor.highestVersion;
bangH, bangNumber => NULL;
ENDCASE => ReportFSError[illegalName, h, file, "Create, version part error"];
desiredMode ← GetCreateMode[h, dH];
tempNameOnServer ← CreateTempName[realBase];
[rpcH, c] ← ObtainRPCHandleAndConversation[h];
createReply ← SunNFSClient.Create[rpcH, c,
[dH.fHandle, Rope.ToRefText[tempNameOnServer]],
SunNFS.SAttr[
mode ~ defaultCreateMode,
uid~CARD.LAST, -- => default
gid~CARD.LAST, -- => default
size~CARD.LAST, -- => default
atime~[CARD.LAST, CARD.LAST], -- => default
mtime~[CARD.LAST, CARD.LAST] -- => default
]
! SunRPC.Error => ReportRPCError[code, h, file, NIL]];
SELECT createReply.status
FROM
ok => NULL;
ENDCASE => {
ReportNFSError[createReply.status, h, file, NIL];
};
buffer ← RefText.ObtainScratch[nfsBufferBytes];
offset ← 0;
DO
bytesRead, bytesWanted, delta: NAT;
bytesWanted ← buffer.maxLength;
delta ← (offset + bytesWanted) MOD serverBlocksize;
IF delta < bytesWanted THEN bytesWanted ← bytesWanted - delta;
bytesRead ← IO.GetBlock[str, buffer, 0, bytesWanted];
IF bytesRead = 0 THEN EXIT;
reply ← SunNFSClient.Write[rpcH, c, createReply.file, offset, bytesRead, 0, buffer
! SunRPC.Error => ReportRPCError[code, h, file]];
SELECT reply.status
FROM
ok => NULL;
ENDCASE => ReportNFSError[reply.status, h, file];
offset ← offset + bytesRead;
ENDLOOP;
RefText.ReleaseScratch[buffer]; buffer ← NIL;
reply ← SunNFSClient.Setattr[rpcH, c, createReply.file,
SunNFS.SAttr[
mode ~ desiredMode,
uid~CARD.LAST, -- => no change
gid~CARD.LAST, -- => no change
size~CARD.LAST, -- => no change
atime~[CARD.LAST, CARD.LAST], -- => no change
mtime~
IF created # BasicTime.nullGMT
THEN SunTimeFromGMT[created] -- the specified one
ELSE [CARD.LAST, CARD.LAST] -- => no change
]
! SunRPC.Error => ReportRPCError[code, h, file]];
SELECT reply.status
FROM
ok => NULL;
ENDCASE => ReportNFSError[reply.status, h, file];
ReleaseRPCHandleAndConversation[h, rpcH, c]; rpcH ← NIL;
version ← AtomicallyRename[h, dH, createReply.file, tempNameOnServer, dH, realBase, specifiedVersion, TRUE];
SELECT vI
FROM
bangNumber => createCaseFile ← (CheckCaseFile[h, dH, realBase] = NIL);
ENDCASE => createCaseFile ← (version = Version[1]);
IF createCaseFile
THEN {
ResetNameReader[nR, -1];
[base~realBase] ← ReadBaseComponent[nR~nR, case~TRUE, stripVersion~TRUE];
CreateCaseFile[h, dH, realBase ! FS.Error => CONTINUE ];
};
UnPinRemoteDirPath[dH]; dH ← NIL;
IF proc # NIL THEN [] ← proc[version];
};