Add options to give somewhat better compatibility with the AFP server in OS X 10.5.

*The OS X server doesn't support ProDOS-type file type info, so trying to set it will give an error. This normally causes GS/OS to give an error when creating a file. There is now an option to ignore the error and proceed with creating the file, although the file type still won't be set.

*The OS X server seems to restrict each write operation to a small size based on the ASP quantum, so there is now an option for this. Using this option means we may write less than requested, but the AppleShare FST can detect this and proceed to write the rest.
This commit is contained in:
Stephen Heumann 2017-04-22 18:46:26 -05:00
parent 898c4e531c
commit c4286a024e
5 changed files with 127 additions and 26 deletions

View File

@ -51,6 +51,8 @@
#define useLargeReadsItem 302
#define forceAFP22Item 303
#define fakeSleepItem 304
#define useLargeWritesItem 305
#define ignoreErrorsSettingFileTypesItem 306
#define fstMissingError 3000
#define noEasyMountError 3001
@ -112,7 +114,8 @@ Word modifiers = 0;
char zoneBuf[ZONE_MAX + 1];
char AFPOverTCPZone[] = "AFP over TCP";
unsigned int flags = fLargeReads; /* for AFP over TCP connections */
/* Default flags for AFP over TCP connections */
unsigned int flags = fLargeReads | fLargeWrites;
void fillEasyMountRec(char *server, char *zone, char *volume, char *user,
char *password, char *volpass)
@ -510,6 +513,14 @@ void DoHit(long ctlID, CtlRecHndl ctlHandle)
} else if (menuItem == fakeSleepItem) {
flags ^= fFakeSleep;
CheckMItem((flags & fFakeSleep) ? TRUE : FALSE, fakeSleepItem);
} else if (menuItem == useLargeWritesItem) {
flags ^= fLargeWrites;
CheckMItem((flags & fLargeWrites) ? TRUE : FALSE,
useLargeWritesItem);
} else if (menuItem == ignoreErrorsSettingFileTypesItem) {
flags ^= fIgnoreFileTypeErrors;
CheckMItem((flags & fIgnoreFileTypeErrors) ? TRUE : FALSE,
ignoreErrorsSettingFileTypesItem);
}
SetCtlValue(afpOverTCPOptionsItem, ctlHandle);

View File

@ -98,6 +98,8 @@ resource rIcon (1) {
#define useLargeReadsItem 302
#define forceAFP22Item 303
#define fakeSleepItem 304
#define useLargeWritesItem 305
#define ignoreErrorsSettingFileTypesItem 306
/*
* Controls in the control panel window (for 640 mode or 320 mode)
@ -245,7 +247,14 @@ resource rMenu (optionsMenu) {
optionsMenu, /* menu ID */
refIsResource*menuTitleRefShift + refIsResource*itemRefShift,
optionsMenu, /* menu title ref (not drawn) */
{afpOverTCPOptionsItem, useLargeReadsItem, forceAFP22Item, fakeSleepItem};
{
afpOverTCPOptionsItem,
useLargeReadsItem,
useLargeWritesItem,
forceAFP22Item,
fakeSleepItem,
ignoreErrorsSettingFileTypesItem
};
};
resource rPString(optionsMenu,noCrossBank) { "" };
@ -267,6 +276,15 @@ resource rMenuItem (useLargeReadsItem) {
};
resource rPString(useLargeReadsItem,noCrossBank) { "Use Large Reads" };
resource rMenuItem (useLargeWritesItem) {
useLargeWritesItem, /* menu item ID */
"","",
$12,
refIsResource*itemTitleRefShift,
useLargeWritesItem /* menu item title ref */
};
resource rPString(useLargeWritesItem,noCrossBank) { "Use Large Writes" };
resource rMenuItem (forceAFP22Item) {
forceAFP22Item, /* menu item ID */
"","",
@ -285,6 +303,17 @@ resource rMenuItem (fakeSleepItem) {
};
resource rPString(fakeSleepItem,noCrossBank) { "Fake Sleep to Keep Alive" };
resource rMenuItem (ignoreErrorsSettingFileTypesItem) {
ignoreErrorsSettingFileTypesItem, /* menu item ID */
"","",
0,
refIsResource*itemTitleRefShift,
ignoreErrorsSettingFileTypesItem /* menu item title ref */
};
resource rPString(ignoreErrorsSettingFileTypesItem,noCrossBank) {
"Ignore Errors Setting File Types"
};
/*
* Controls in the help window
*/

View File

@ -10,7 +10,9 @@
AFPOptions afpOptions[] =
{
{"LR", fLargeReads},
{"LW", fLargeWrites},
{"22", fForceAFP22},
{"FS", fFakeSleep},
{"IE", fIgnoreFileTypeErrors},
{0, 0}
};

View File

@ -4,6 +4,8 @@
#define fLargeReads 0x0001
#define fForceAFP22 0x0002
#define fFakeSleep 0x0004
#define fIgnoreFileTypeErrors 0x0008
#define fLargeWrites 0x0010
typedef struct AFPOptions {
char *optString;

View File

@ -26,9 +26,32 @@ typedef struct FPReadRec {
Byte NewLineChar;
} FPReadRec;
typedef struct FPWriteRec {
Word CommandCode; /* includes pad byte */
Word OForkRecNum;
LongWord Offset;
LongWord ReqCount;
} FPWriteRec;
typedef struct FPSetFileDirParmsRec {
Word CommandCode; /* includes pad byte */
Word VolumeID;
LongWord DirectoryID;
Word Bitmap;
Byte PathType;
/* Pathname and parameters follow */
} FPSetFileDirParmsRec;
#define kFPRead 27
#define kFPLogin 18
#define kFPZzzzz 122
#define kFPSetFileDirParms 35
#define kFPBitmapErr (-5004L)
#define kFPProDOSInfoBit 0x2000 /* In file/directory bitmaps */
#define ASPQuantumSize 4624
/* For forced AFP 2.2 login */
static Byte loginBuf[100];
@ -196,13 +219,13 @@ ret:
* after every command we send. This avoids having the server
* disconnect us because we can't send tickles for a while.
*
* This implementation is designed to work with Netatalk:
* -Apple's docs say FPZzzzz was introduced with AFP 2.3, but Netatalk
* supports it with AFP 2.2 and doesn't support AFP 2.3 at all.
* -Apple's docs also say there is no reply to FPZzzzz, but Netatalk
* send a reply with four bytes of data.
* Netatalk includes comments indicating Apple's implementation in OS X
* may really work more like Netatalk, but I haven't checked this.
* This implementation differs from Apple's specifications in a couple
* respects, but matches the actual behavior of the servers I've tried:
*
* -Apple's docs say FPZzzzz was introduced with AFP 2.3, but Netatalk and
* OS X 10.5 support it with AFP 2.2 and doesn't support AFP 2.3 at all.
* -Apple's docs show no reply block for FPZzzzz, but Netatalk and
* OS X 10.5 send a reply with four bytes of data.
*/
if ((sess->atipMapping.flags & fFakeSleep)
&& sess->loggedIn && commandRec->result == 0
@ -355,12 +378,27 @@ static void DoSPCommand(Session *sess, ASPCommandRec *commandRec) {
}
static void DoSPWrite(Session *sess, ASPWriteRec *commandRec) {
LongWord dataLength;
sess->request.flags = DSI_REQUEST;
sess->request.command = DSIWrite;
sess->request.requestID = htons(sess->nextRequestID++);
sess->request.writeOffset = htonl(commandRec->cmdBlkLength);
dataLength = commandRec->writeDataLength;
/*
* If requested, limit the data size of a single DSIWrite command to 4623.
* This is necessary to make writes work on OS X (and others?).
*/
if (!(sess->atipMapping.flags & fLargeWrites)
&& dataLength > ASPQuantumSize - 1)
{
dataLength = ASPQuantumSize - 1;
((FPReadRec*)commandRec->cmdBlkAddr)->ReqCount = htonl(dataLength);
}
sess->request.totalDataLength =
htonl(commandRec->cmdBlkLength + commandRec->writeDataLength);
htonl(dataLength + commandRec->cmdBlkLength);
sess->replyBuf = (void*)(commandRec->replyBufferAddr & 0x00FFFFFF);
sess->replyBufLen = commandRec->replyBufferLen;
@ -411,13 +449,32 @@ void FinishASPCommand(Session *sess) {
((ASPCommandRec*)(sess->spCommandRec))->cmdResult =
sess->reply.errorCode;
((ASPCommandRec*)(sess->spCommandRec))->replyLength = dataLength;
/*
* If requested by user, ignore errors when setting ProDOS-style
* filetype info. This allows files to be written to servers running
* old versions of OS X, although filetypes are not set correctly.
*/
if ((sess->atipMapping.flags & fIgnoreFileTypeErrors)
&& ((ASPCommandRec*)(sess->spCommandRec))->cmdBlkLength
> sizeof(FPSetFileDirParmsRec)
&& *(Byte*)(((ASPCommandRec*)(sess->spCommandRec))->cmdBlkAddr)
== kFPSetFileDirParms
&& (((FPSetFileDirParmsRec*)(((ASPCommandRec*)(sess->spCommandRec))
->cmdBlkAddr))->Bitmap & htons(kFPProDOSInfoBit))
&& sess->reply.errorCode == htonl((LongWord)kFPBitmapErr))
{
((ASPCommandRec*)(sess->spCommandRec))->cmdResult = 0;
}
break;
case aspWriteCommand:
((ASPWriteRec*)(sess->spCommandRec))->cmdResult =
sess->reply.errorCode;
((ASPWriteRec*)(sess->spCommandRec))->replyLength = dataLength;
((ASPWriteRec*)(sess->spCommandRec))->writtenLength =
((ASPWriteRec*)(sess->spCommandRec))->writeDataLength;
ntohl(sess->request.totalDataLength)
- ((ASPWriteRec*)(sess->spCommandRec))->cmdBlkLength;
break;
}