struct afs_FSStats afs_fsstats;
-int LogLevel = 0;
int supported = 1;
int Console = 0;
afs_int32 BlocksSpare = 1024; /* allow 1 MB overruns */
afs_int32 PctSpare;
extern afs_int32 implicitAdminRights;
extern afs_int32 readonlyServer;
+extern afs_int32 adminwriteServer;
extern int CopyOnWrite_calls, CopyOnWrite_off0, CopyOnWrite_size0;
extern afs_fsize_t CopyOnWrite_maxsize;
Error errorCode = 0; /* return code to caller */
struct rx_connection *tcon = rx_ConnectionOf(acall);
- rx_KeepAliveOff(acall);
-
if ((errorCode = CheckVnodeWithCall(Fid, volptr, cbv, targetptr, locktype)))
goto gvpdone;
#endif /* ADMIN_IMPLICIT_LOOKUP */
}
gvpdone:
- if (errorCode)
- rx_KeepAliveOn(acall);
return errorCode;
} /*GetVolumePackage */
{
Error fileCode = 0; /* Error code returned by the volume package */
- rx_KeepAliveOff(acall);
if (parentwhentargetnotdir) {
VPutVnode(&fileCode, parentwhentargetnotdir);
assert_vnode_success_or_salvaging(fileCode);
if (volptr) {
VPutVolumeWithCall(volptr, cbv);
}
- rx_KeepAliveOn(acall);
if (*client) {
PutClient(client);
} /*VolumeRootVnode */
+/**
+ * Check if server can perform writes.
+ *
+ * This functions checks if the fileserver is read-only for the client received
+ * as an argument. Read-only fileservers allow write requests for members of
+ * system:administrators when started with both -readonly and -admin-write.
+ *
+ * @param[in] client calling user
+ *
+ * @return 1 if not read-only for this user; 0 otherwise
+ */
+static int
+IsWriteAllowed(struct client *client)
+{
+ if (readonlyServer) {
+ if (adminwriteServer && !VanillaUser(client)) {
+ /* admins can write */
+ return 1;
+ }
+ return 0;
+ }
+ return 1;
+}
+
/*
* Check if target file has the proper access permissions for the Fetch
* (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
AUD_END);
}
} else { /* a store operation */
+ if (!IsWriteAllowed(client)) {
+ return (VREADONLY);
+ }
if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
&& (CallingRoutine != CHK_STOREACL)
&& (targetptr->disk.type == vFile)) {
* unless you are a system administrator */
/****** InStatus->Owner && UnixModeBits better be SET!! */
if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
- if (readonlyServer)
- return (VREADONLY);
- else if (VanillaUser(client))
+ if (VanillaUser(client))
return (EPERM); /* Was EACCES */
else
osi_audit(PrivilegeEvent, 0, AUD_ID,
(client ? client->z.ViceId : 0), AUD_INT,
CallingRoutine, AUD_END);
} else {
- if (readonlyServer) {
- return (VREADONLY);
- }
if (CallingRoutine == CHK_STOREACL) {
if (!(rights & PRSFS_ADMINISTER)
&& !VolumeOwner(client, targetptr))
/* watch for chowns and chgrps */
if (CHOWN(InStatus, targetptr)
|| CHGRP(InStatus, targetptr)) {
- if (readonlyServer)
- return (VREADONLY);
- else if (VanillaUser(client))
+ if (VanillaUser(client))
return (EPERM); /* Was EACCES */
else
osi_audit(PrivilegeEvent, 0, AUD_ID,
#else
(InStatus->UnixModeBits & (S_ISUID | S_ISGID)) != 0) {
#endif
- if (readonlyServer)
- return (VREADONLY);
if (VanillaUser(client))
return (EACCES);
else
CallingRoutine, AUD_END);
}
if (CallingRoutine == CHK_STOREDATA) {
- if (readonlyServer)
- return (VREADONLY);
if (!(rights & PRSFS_WRITE))
return (EACCES);
/* Next thing is tricky. We want to prevent people
#endif
if ((targetptr->disk.type != vDirectory)
&& (!(targetptr->disk.modeBits & OWNERWRITE))) {
- if (readonlyServer)
- return (VREADONLY);
if (VanillaUser(client))
return (EACCES);
else
AUD_INT, CallingRoutine, AUD_END);
}
} else { /* a status store */
- if (readonlyServer)
- return (VREADONLY);
if (targetptr->disk.type == vDirectory) {
if (!(rights & PRSFS_DELETE)
&& !(rights & PRSFS_INSERT))
/* check that the file is in the directory */
SetDirHandle(dir, parentptr);
- if (afs_dir_Lookup(dir, Name, fileFid))
- return (ENOENT);
+ errorCode = afs_dir_Lookup(dir, Name, fileFid);
+ if (errorCode && errorCode != ENOENT) {
+ errorCode = EIO;
+ }
+ if (errorCode) {
+ return errorCode;
+ }
fileFid->Volume = V_id(volptr);
/* just-in-case check for something causing deadlock */
/* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */
static afs_int32
-CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
+CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode,
+ struct client *client)
{
- if (readonlyServer)
+ if (!IsWriteAllowed(client))
return (VREADONLY);
if (!(rights & Prfs_Mode))
return (EACCES);
GetStatus(targetptr, OutStatus, rights, anyrights,
&tparentwhentargetnotdir);
- rx_KeepAliveOn(acall); /* I/O done */
-
/* if a r/w volume, promise a callback to the caller */
if (VolumeWriteable(volptr))
SetCallBackStruct(AddCallBack(client->z.host, Fid), CallBack);
&rights, &anyrights)))
goto Bad_FetchStatus;
- rx_KeepAliveOn(acall);
-
/* set volume synchronization information */
SetVolumeSync(Sync, volptr);
&rights, &anyrights)))
goto Bad_BulkStatus;
- rx_KeepAliveOn(acall);
-
/* set volume synchronization information, but only once per call */
if (i == 0)
SetVolumeSync(Sync, volptr);
&rights, &anyrights))) {
tstatus = &OutStats->AFSBulkStats_val[i];
+ tstatus->InterfaceVersion = 1;
if (thost->z.hostFlags & HERRORTRANS) {
tstatus->errorCode = sys_error_to_et(errorCode);
} else {
continue;
}
- rx_KeepAliveOn(acall);
-
/* set volume synchronization information, but only once per call */
if (!VolSync_set) {
SetVolumeSync(Sync, volptr);
CHK_FETCHSTATUS, 0))) {
tstatus = &OutStats->AFSBulkStats_val[i];
+ tstatus->InterfaceVersion = 1;
if (thost->z.hostFlags & HERRORTRANS) {
tstatus->errorCode = sys_error_to_et(errorCode);
} else {
goto Bad_StoreData;
}
- rx_KeepAliveOn(acall);
-
/* set volume synchronization information */
SetVolumeSync(Sync, volptr);
*/
if (parentwhentargetnotdir != NULL) {
tparentwhentargetnotdir = *parentwhentargetnotdir;
- rx_KeepAliveOff(acall);
VPutVnode(&fileCode, parentwhentargetnotdir);
- rx_KeepAliveOn(acall);
assert_vnode_success_or_salvaging(fileCode);
parentwhentargetnotdir = NULL;
}
if (errorCode && (!targetptr->changed_newTime))
goto Bad_StoreData;
- rx_KeepAliveOff(acall);
/* Update the status of the target's vnode */
Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
targetptr, volptr, 0, 0);
- rx_KeepAliveOn(acall);
/* Get the updated File's status back to the caller */
GetStatus(targetptr, OutStatus, rights, anyrights,
VVnodeWriteToRead(&errorCode, targetptr);
assert_vnode_success_or_salvaging(errorCode);
- rx_KeepAliveOn(acall);
-
/* break call backs on the directory */
BreakCallBack(client->z.host, Fid, 0);
(parentwhentargetnotdir ? parentwhentargetnotdir
: targetptr), volptr, 0, 0);
- rx_KeepAliveOn(acall);
-
/* convert the write lock to a read lock before breaking callbacks */
VVnodeWriteToRead(&errorCode, targetptr);
assert_vnode_success_or_salvaging(errorCode);
SetVolumeSync(Sync, volptr);
/* Does the caller has delete (& write) access to the parent directory? */
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE, client))) {
goto Bad_RemoveFile;
}
parentptr->disk.linkCount,
client->z.InSameNetwork);
- rx_KeepAliveOn(acall);
-
/* Return the updated parent dir's status back to caller */
GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
SetVolumeSync(Sync, volptr);
/* Can we write (and insert) onto the parent directory? */
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))) {
goto Bad_CreateFile;
}
Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
parentptr, volptr, 0, 0);
- rx_KeepAliveOn(acall);
-
/* set up the return status for the parent dir and the newly created file, and since the newly created file is owned by the creator, give it PRSFS_ADMINISTER to tell the client its the owner of the file */
GetStatus(targetptr, OutFidStatus, rights | PRSFS_ADMINISTER, anyrights, parentptr);
GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
/* set volume synchronization information */
SetVolumeSync(Sync, volptr);
- if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
+ if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE, client))) {
goto Bad_Rename;
}
- if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
+ if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT,
+ client))) {
goto Bad_Rename;
}
SetDirHandle(&newdir, newvptr);
/* Lookup the file to delete its vnode */
- if (afs_dir_Lookup(&olddir, OldName, &fileFid)) {
- errorCode = ENOENT;
+ errorCode = afs_dir_Lookup(&olddir, OldName, &fileFid);
+ if (errorCode && errorCode != ENOENT) {
+ errorCode = EIO;
+ }
+ if (errorCode) {
goto Bad_Rename;
}
if (fileFid.Vnode == oldvptr->vnodeNumber
}
/* Lookup the new file */
- if (!(afs_dir_Lookup(&newdir, NewName, &newFileFid))) {
- if (readonlyServer) {
+ code = afs_dir_Lookup(&newdir, NewName, &newFileFid);
+ if (code && code != ENOENT) {
+ errorCode = EIO;
+ goto Bad_Rename;
+ }
+ if (!code) {
+ if (!IsWriteAllowed(client)) {
errorCode = VREADONLY;
goto Bad_Rename;
}
struct AFSFid unused;
code = afs_dir_Lookup(&filedir, "..", &unused);
+ if (code && code != ENOENT) {
+ errorCode = EIO;
+ goto Bad_Rename;
+ }
if (code == ENOENT) {
/* only update .. if it doesn't already exist */
updatefile = 1;
NewName, errno));
if ((errno != ENOENT) && (errno != EIO)
&& (errno != ENXIO))
- ViceLog(0, ("Do we need to fsck?"));
+ ViceLog(0, ("Do we need to fsck?\n"));
}
}
VN_SET_INO(newfileptr, (Inode) 0);
assert_vnode_success_or_salvaging(errorCode);
}
- rx_KeepAliveOn(acall);
-
/* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */
BreakCallBack(client->z.host, NewDirFid, 0);
if (oldvptr != newvptr) {
Bad_Rename:
if (newfileptr) {
- rx_KeepAliveOff(acall);
VPutVnode(&fileCode, newfileptr);
assert_vnode_success_or_salvaging(fileCode);
}
SetVolumeSync(Sync, volptr);
/* Does the caller has insert (and write) access to the parent directory? */
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)))
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client)))
goto Bad_SymLink;
/*
* to do this.
*/
if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
- if (readonlyServer) {
+ if (!IsWriteAllowed(client)) {
errorCode = VREADONLY;
goto Bad_SymLink;
}
VVnodeWriteToRead(&errorCode, parentptr);
assert_vnode_success_or_salvaging(errorCode);
- rx_KeepAliveOn(acall);
-
/* break call back on the parent dir */
BreakCallBack(client->z.host, DirFid, 0);
SetVolumeSync(Sync, volptr);
/* Can the caller insert into the parent directory? */
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))) {
goto Bad_Link;
}
VVnodeWriteToRead(&errorCode, parentptr);
assert_vnode_success_or_salvaging(errorCode);
- rx_KeepAliveOn(acall);
-
/* break call back on DirFid */
BreakCallBack(client->z.host, DirFid, 0);
/*
* implcit a access that goes with dir ownership, and proceed to
* subvert quota in the volume.
*/
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))
- || (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))
+ || (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE,
+ client))) {
#else
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))) {
#endif /* DIRCREATE_NEED_WRITE */
goto Bad_MakeDir;
}
VVnodeWriteToRead(&errorCode, parentptr);
assert_vnode_success_or_salvaging(errorCode);
- rx_KeepAliveOn(acall);
-
/* break call back on DirFid */
BreakCallBack(client->z.host, DirFid, 0);
SetVolumeSync(Sync, volptr);
/* Does the caller has delete (&write) access to the parent dir? */
- if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
+ if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE, client))) {
goto Bad_RemoveDir;
}
VVnodeWriteToRead(&errorCode, parentptr);
assert_vnode_success_or_salvaging(errorCode);
- rx_KeepAliveOn(acall);
-
/* break call back on DirFid and fileFid */
BreakCallBack(client->z.host, DirFid, 0);
/* if no more locks left, a callback would be triggered here */
if (targetptr->disk.lock.lockCount <= 0) {
- rx_KeepAliveOn(acall);
/* convert the write lock to a read lock before breaking callbacks */
VVnodeWriteToRead(&errorCode, targetptr);
assert_vnode_success_or_salvaging(errorCode);
afs_int32 * a_timeP, AFS_CollData * a_dataP)
{ /*SRXAFS_GetXStats */
+ struct client *t_client = NULL; /* tmp ptr to client data */
+ struct rx_connection *tcon = rx_ConnectionOf(a_call);
int code; /*Return value */
afs_int32 *dataBuffP; /*Ptr to data to be returned */
afs_int32 dataBytes; /*Bytes in data buffer */
struct fsstats fsstats;
- fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETXSTATS);
-
/*
- * Record the time of day and the server version number.
+ * Note: This function intentionally omits CallPreamble()
+ * to avoid issuing TellMeAboutYourself() calls to
+ * simple clients which are only gathering stats.
*/
+
+ fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETXSTATS);
+
+ t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
+
+ /* Return the server's time of day and xstat version number. */
*a_srvVersionNumP = AFS_XSTAT_VERSION;
*a_timeP = (afs_int32) time(NULL);
-
- /*
- * Stuff the appropriate data in there (assume victory)
- */
code = 0;
- ViceLog(1,
- ("Received GetXStats call for collection %d\n",
- a_collectionNumber));
-
-#if 0
- /*
- * We're not keeping stats, so just return successfully with
- * no data.
- */
- a_dataP->AFS_CollData_len = 0;
- a_dataP->AFS_CollData_val = NULL;
-#endif /* 0 */
+ osi_auditU(a_call, GetXStatsEvent,
+ AUD_ID, t_client ? t_client->z.ViceId : 0,
+ AUD_INT, a_clientVersionNum,
+ AUD_INT, a_collectionNumber, AUD_END);
switch (a_collectionNumber) {
case AFS_XSTATSCOLL_CALL_INFO:
- /*
- * Pass back all the call-count-related data.
- *
- * >>> We are forced to allocate a separate area in which to
- * >>> put this stuff in by the RPC stub generator, since it
- * >>> will be freed at the tail end of the server stub code.
- */
-#if 0
- /*
- * I don't think call-level stats are being collected yet
- * for the File Server.
- */
- dataBytes = sizeof(struct afs_Stats);
- dataBuffP = malloc(dataBytes);
- memcpy(dataBuffP, &afs_cmstats, dataBytes);
- a_dataP->AFS_CollData_len = dataBytes >> 2;
- a_dataP->AFS_CollData_val = dataBuffP;
-#else
+ /* The call info collection type is not implemented. */
a_dataP->AFS_CollData_len = 0;
a_dataP->AFS_CollData_val = NULL;
-#endif /* 0 */
break;
case AFS_XSTATSCOLL_PERF_INFO:
/*
* Pass back all the regular performance-related data.
*
- * >>> We are forced to allocate a separate area in which to
- * >>> put this stuff in by the RPC stub generator, since it
- * >>> will be freed at the tail end of the server stub code.
+ * Allocate a separate area in which to put this stuff in
+ * by the RPC stub generator, since it will be freed at the
+ * tail end of the server stub code.
*/
-
afs_perfstats.numPerfCalls++;
FillPerfValues(&afs_perfstats);
-
- /*
- * Don't overwrite the spares at the end.
- */
-
dataBytes = sizeof(struct afs_PerfStats);
- dataBuffP = malloc(dataBytes);
+ dataBuffP = calloc(1, dataBytes);
memcpy(dataBuffP, &afs_perfstats, dataBytes);
- a_dataP->AFS_CollData_len = dataBytes >> 2;
+ a_dataP->AFS_CollData_len = dataBytes / sizeof(afs_int32);
a_dataP->AFS_CollData_val = dataBuffP;
break;
* We have to stuff the basic, overall numbers in, but the
* detailed numbers are kept in the structure already.
*
- * >>> We are forced to allocate a separate area in which to
- * >>> put this stuff in by the RPC stub generator, since it
- * >>> will be freed at the tail end of the server stub code.
+ * Allocate a separate area in which to put this stuff in
+ * by the RPC stub generator, since it will be freed at the
+ * tail end of the server stub code.
*/
-
afs_perfstats.numPerfCalls++;
afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
FillPerfValues(&afs_FullPerfStats.overall);
-
- /*
- * Don't overwrite the spares at the end.
- */
-
dataBytes = sizeof(struct fs_stats_FullPerfStats);
- dataBuffP = malloc(dataBytes);
+ dataBuffP = calloc(1, dataBytes);
memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
- a_dataP->AFS_CollData_len = dataBytes >> 2;
+ a_dataP->AFS_CollData_len = dataBytes / sizeof(afs_int32);
a_dataP->AFS_CollData_val = dataBuffP;
break;
afs_perfstats.numPerfCalls++;
dataBytes = sizeof(struct cbcounters);
- dataBuffP = malloc(dataBytes);
+ dataBuffP = calloc(1, dataBytes);
{
extern struct cbcounters cbstuff;
dataBuffP[0]=cbstuff.DeleteFiles;
dataBuffP[15]=cbstuff.GSS5;
}
- a_dataP->AFS_CollData_len = dataBytes >> 2;
+ a_dataP->AFS_CollData_len = dataBytes / sizeof(afs_int32);
a_dataP->AFS_CollData_val = dataBuffP;
break;
-
default:
- /*
- * Illegal collection number.
- */
+ /* Illegal collection number. */
a_dataP->AFS_CollData_len = 0;
a_dataP->AFS_CollData_val = NULL;
code = 1;
&rights, &anyrights)))
goto Bad_SetVolumeStatus;
- if (readonlyServer) {
+ if (!IsWriteAllowed(client)) {
errorCode = VREADONLY;
goto Bad_SetVolumeStatus;
}
afs_int32
SRXAFS_GetRootVolume(struct rx_call * acall, char **VolumeName)
{
-#ifdef notdef
- int fd;
- int len;
- char *temp;
- struct rx_connection *tcon;
- struct host *thost;
- Error errorCode = 0;
-#endif
struct fsstats fsstats;
fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETROOTVOLUME);
} /*SRXAFS_GetRootVolume */
-/* still works because a struct CBS is the same as a struct AFSOpaque */
afs_int32
SRXAFS_CheckToken(struct rx_call * acall, afs_int32 AfsId,
struct AFSOpaque * Token)
FDH_CLOSE(lhp);
if (*lc < 0)
return -1;
- *size = OS_SIZE(fdP->fd_fd);
+ *size = FDH_SIZE(fdP);
return (*size == -1) ? -1 : 0;
#else
struct afs_stat status;
inet_ntoa(logHostAddr), ntohs(rxr_PortOf(rx_ConnectionOf(Call)))));
return ENOENT; /* is this proper error code? */
} else {
- rx_KeepAliveOff(Call);
/*
* See if the file has several links (from other volumes). If it
* does, then we have to make a copy before changing it to avoid
sys2et[EDQUOT] = UAEDQUOT;
sys2et[ENOMEDIUM] = UAENOMEDIUM;
sys2et[EMEDIUMTYPE] = UAEMEDIUMTYPE;
+ sys2et[ECANCELED] = UAECANCELED;
+ sys2et[ENOTRECOVERABLE] = UAENOTRECOVERABLE;
+ sys2et[ENOTSUP] = UAENOTSUP;
+ sys2et[EOTHER] = UAEOTHER;
+ sys2et[EOWNERDEAD] = UAEOWNERDEAD;
+ sys2et[EPROCLIM] = UAEPROCLIM;
+ sys2et[EDISCON] = UAEDISCON;
sys2et[EIO] = UAEIO;
}