mirror of
https://git.openafs.org/openafs.git
synced 2025-01-23 01:11:13 +00:00
6c6f9dce24
- Remove some further warnings from the vol directory - Add volutil_PartitionName2_r to afsutil_prototypes.h - Export vol_prototypes.h so it can be used elsewhere in the tree Reviewed-on: http://gerrit.openafs.org/17 Reviewed-by: Derrick Brashear <shadow@dementia.org> Reviewed-by: Russ Allbery <rra@stanford.edu> Verified-by: Derrick Brashear <shadow@dementia.org>
369 lines
9.9 KiB
C
369 lines
9.9 KiB
C
/*
|
|
* Copyright 2000, International Business Machines Corporation and others.
|
|
* All Rights Reserved.
|
|
*
|
|
* This software has been released under the terms of the IBM Public
|
|
* License. For details, see the LICENSE file in the top-level source
|
|
* directory or online at http://www.openafs.org/dl/license10.html
|
|
*/
|
|
|
|
/*
|
|
System: VICE-TWO
|
|
Module: vutil.c
|
|
Institution: The Information Technology Center, Carnegie-Mellon University
|
|
|
|
*/
|
|
|
|
#include <afsconfig.h>
|
|
#include <afs/param.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#ifdef AFS_NT40_ENV
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#else
|
|
#include <sys/time.h>
|
|
#include <sys/file.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#ifdef AFS_PTHREAD_ENV
|
|
#include <assert.h>
|
|
#else /* AFS_PTHREAD_ENV */
|
|
#include <afs/assert.h>
|
|
#endif /* AFS_PTHREAD_ENV */
|
|
|
|
#include <rx/xdr.h>
|
|
#include <afs/afsint.h>
|
|
#include "nfs.h"
|
|
#include <afs/errors.h>
|
|
#include "lock.h"
|
|
#include "lwp.h"
|
|
#include <afs/afssyscalls.h>
|
|
#include "ihandle.h"
|
|
#include <afs/afsutil.h>
|
|
#ifdef AFS_NT40_ENV
|
|
#include "ntops.h"
|
|
#include <io.h>
|
|
#endif
|
|
#include "vnode.h"
|
|
#include "volume.h"
|
|
#include "partition.h"
|
|
#include "viceinode.h"
|
|
|
|
#include "volinodes.h"
|
|
#include "vol_prototypes.h"
|
|
|
|
#ifdef AFS_AIX_ENV
|
|
#include <sys/lockf.h>
|
|
#endif
|
|
#if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
#ifdef O_LARGEFILE
|
|
#define afs_open open64
|
|
#else /* !O_LARGEFILE */
|
|
#define afs_open open
|
|
#endif /* !O_LARGEFILE */
|
|
|
|
/*@printflike@*/ extern void Log(const char *format, ...);
|
|
|
|
#define nFILES (sizeof (stuff)/sizeof(struct stuff))
|
|
|
|
/* Note: the volume creation functions herein leave the destroyMe flag in the
|
|
volume header ON: this means that the volumes will not be attached by the
|
|
file server and WILL BE DESTROYED the next time a system salvage is performed */
|
|
|
|
static void
|
|
RemoveInodes(Device dev, VolumeId vid)
|
|
{
|
|
register int i;
|
|
IHandle_t *handle;
|
|
|
|
/* This relies on the fact that IDEC only needs the device and NT only
|
|
* needs the dev and vid to decrement volume special files.
|
|
*/
|
|
IH_INIT(handle, dev, vid, -1);
|
|
for (i = 0; i < nFILES; i++) {
|
|
Inode inode = *stuff[i].inode;
|
|
if (VALID_INO(inode))
|
|
IH_DEC(handle, inode, vid);
|
|
}
|
|
IH_RELEASE(handle);
|
|
}
|
|
|
|
Volume *
|
|
VCreateVolume(Error * ec, char *partname, VolId volumeId, VolId parentId)
|
|
{ /* Should be the same as volumeId if there is
|
|
* no parent */
|
|
Volume *retVal;
|
|
VOL_LOCK;
|
|
retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
|
|
VOL_UNLOCK;
|
|
return retVal;
|
|
}
|
|
|
|
Volume *
|
|
VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId)
|
|
{ /* Should be the same as volumeId if there is
|
|
* no parent */
|
|
VolumeDiskData vol;
|
|
int fd, i;
|
|
char headerName[32], volumePath[64];
|
|
Device device;
|
|
struct DiskPartition64 *partition;
|
|
struct VolumeDiskHeader diskHeader;
|
|
IHandle_t *handle;
|
|
FdHandle_t *fdP;
|
|
Inode nearInode = 0;
|
|
char *part, *name;
|
|
|
|
*ec = 0;
|
|
memset(&vol, 0, sizeof(vol));
|
|
vol.id = volumeId;
|
|
vol.parentId = parentId;
|
|
vol.copyDate = time(0); /* The only date which really means when this
|
|
* @i(instance) of this volume was created.
|
|
* Creation date does not mean this */
|
|
|
|
/* Initialize handle for error case below. */
|
|
handle = NULL;
|
|
|
|
/* Verify that the parition is valid before writing to it. */
|
|
if (!(partition = VGetPartition_r(partname, 0))) {
|
|
Log("VCreateVolume: partition %s is not in service.\n", partname);
|
|
*ec = VNOVOL;
|
|
return NULL;
|
|
}
|
|
#if defined(NEARINODE_HINT)
|
|
nearInodeHash(volumeId, nearInode);
|
|
nearInode %= partition->f_files;
|
|
#endif
|
|
VGetVolumePath(ec, vol.id, &part, &name);
|
|
if (*ec == VNOVOL || !strcmp(partition->name, part)) {
|
|
/* this case is ok */
|
|
} else {
|
|
/* return EXDEV if it's a clone to an alternate partition
|
|
* otherwise assume it's a move */
|
|
if (vol.parentId != vol.id) {
|
|
*ec = EXDEV;
|
|
return NULL;
|
|
}
|
|
}
|
|
VLockPartition_r(partname);
|
|
memset(&tempHeader, 0, sizeof(tempHeader));
|
|
tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
|
|
tempHeader.stamp.version = VOLUMEHEADERVERSION;
|
|
tempHeader.id = vol.id;
|
|
tempHeader.parent = vol.parentId;
|
|
vol.stamp.magic = VOLUMEINFOMAGIC;
|
|
vol.stamp.version = VOLUMEINFOVERSION;
|
|
vol.destroyMe = DESTROY_ME;
|
|
(void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_cast_uint32(vol.id));
|
|
(void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s",
|
|
VPartitionPath(partition), headerName);
|
|
fd = afs_open(volumePath, O_CREAT | O_EXCL | O_WRONLY, 0600);
|
|
if (fd == -1) {
|
|
if (errno == EEXIST) {
|
|
Log("VCreateVolume: Header file %s already exists!\n",
|
|
volumePath);
|
|
*ec = VVOLEXISTS;
|
|
} else {
|
|
Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
|
|
*ec = VNOVOL;
|
|
}
|
|
return NULL;
|
|
}
|
|
device = partition->device;
|
|
|
|
for (i = 0; i < nFILES; i++) {
|
|
register struct stuff *p = &stuff[i];
|
|
if (p->obsolete)
|
|
continue;
|
|
#ifdef AFS_NAMEI_ENV
|
|
*(p->inode) =
|
|
IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
|
|
(p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
|
|
INODESPECIAL, p->inodeType, vol.parentId);
|
|
if (!(VALID_INO(*(p->inode)))) {
|
|
if (errno == EEXIST) {
|
|
/* Increment the reference count instead. */
|
|
IHandle_t *lh;
|
|
int code;
|
|
|
|
#ifdef AFS_NT40_ENV
|
|
*(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
|
|
#else
|
|
*(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
|
|
#endif
|
|
IH_INIT(lh, device, parentId, *(p->inode));
|
|
fdP = IH_OPEN(lh);
|
|
if (fdP == NULL) {
|
|
IH_RELEASE(lh);
|
|
goto bad;
|
|
}
|
|
code = IH_INC(lh, *(p->inode), parentId);
|
|
FDH_REALLYCLOSE(fdP);
|
|
IH_RELEASE(lh);
|
|
if (code < 0)
|
|
goto bad;
|
|
continue;
|
|
}
|
|
}
|
|
#else
|
|
*(p->inode) =
|
|
IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
|
|
vol.id, INODESPECIAL, p->inodeType, vol.parentId);
|
|
#endif
|
|
|
|
if (!VALID_INO(*(p->inode))) {
|
|
Log("VCreateVolume: Problem creating %s file associated with volume header %s\n", p->description, volumePath);
|
|
bad:
|
|
if (handle)
|
|
IH_RELEASE(handle);
|
|
RemoveInodes(device, vol.id);
|
|
*ec = VNOVOL;
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
IH_INIT(handle, device, vol.parentId, *(p->inode));
|
|
fdP = IH_OPEN(handle);
|
|
if (fdP == NULL) {
|
|
Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
|
|
PrintInode(NULL, *(p->inode)), errno);
|
|
goto bad;
|
|
}
|
|
if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
|
|
Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
|
|
PrintInode(NULL, *(p->inode)), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
goto bad;
|
|
}
|
|
if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) !=
|
|
sizeof(p->stamp)) {
|
|
Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
|
|
PrintInode(NULL, *(p->inode)), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
goto bad;
|
|
}
|
|
FDH_REALLYCLOSE(fdP);
|
|
IH_RELEASE(handle);
|
|
nearInode = *(p->inode);
|
|
}
|
|
|
|
IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
|
|
fdP = IH_OPEN(handle);
|
|
if (fdP == NULL) {
|
|
Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
|
|
PrintInode(NULL, tempHeader.volumeInfo), errno);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
|
|
Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
|
|
PrintInode(NULL, tempHeader.volumeInfo), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
if (FDH_WRITE(fdP, (char *)&vol, sizeof(vol)) != sizeof(vol)) {
|
|
Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
|
|
PrintInode(NULL, tempHeader.volumeInfo), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
FDH_CLOSE(fdP);
|
|
IH_RELEASE(handle);
|
|
|
|
VolumeHeaderToDisk(&diskHeader, &tempHeader);
|
|
if (write(fd, &diskHeader, sizeof(diskHeader)) != sizeof(diskHeader)) {
|
|
Log("VCreateVolume: Unable to write volume header %s; volume %u not created\n", volumePath, vol.id);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
fsync(fd);
|
|
close(fd);
|
|
return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY));
|
|
}
|
|
|
|
|
|
void
|
|
AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext)
|
|
{
|
|
VOL_LOCK;
|
|
AssignVolumeName_r(vol, name, ext);
|
|
VOL_UNLOCK;
|
|
}
|
|
|
|
void
|
|
AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext)
|
|
{
|
|
register char *dot;
|
|
strncpy(vol->name, name, VNAMESIZE - 1);
|
|
vol->name[VNAMESIZE - 1] = '\0';
|
|
dot = strrchr(vol->name, '.');
|
|
if (dot && (strcmp(dot, ".backup") == 0 || strcmp(dot, ".readonly") == 0))
|
|
*dot = 0;
|
|
if (ext)
|
|
strncat(vol->name, ext, VNAMESIZE - 1 - strlen(vol->name));
|
|
}
|
|
|
|
afs_int32
|
|
CopyVolumeHeader_r(VolumeDiskData * from, VolumeDiskData * to)
|
|
{
|
|
/* The id and parentId fields are not copied; these are inviolate--the to volume
|
|
* is assumed to have already been created. The id's cannot be changed once
|
|
* creation has taken place, since they are embedded in the various inodes associated
|
|
* with the volume. The copydate is also inviolate--it always reflects the time
|
|
* this volume was created (compare with the creation date--the creation date of
|
|
* a backup volume is the creation date of the original parent, because the backup
|
|
* is used to backup the parent volume). */
|
|
Date copydate;
|
|
VolumeId id, parent;
|
|
id = to->id;
|
|
parent = to->parentId;
|
|
copydate = to->copyDate;
|
|
memcpy(to, from, sizeof(*from));
|
|
to->id = id;
|
|
to->parentId = parent;
|
|
to->copyDate = copydate;
|
|
to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
|
|
to->stamp.magic = VOLUMEINFOMAGIC;
|
|
to->stamp.version = VOLUMEINFOVERSION;
|
|
return 0;
|
|
}
|
|
|
|
afs_int32
|
|
CopyVolumeHeader(VolumeDiskData * from, VolumeDiskData * to)
|
|
{
|
|
afs_int32 code;
|
|
|
|
VOL_LOCK;
|
|
code = CopyVolumeHeader_r(from, to);
|
|
VOL_UNLOCK;
|
|
return (code);
|
|
}
|
|
|
|
void
|
|
ClearVolumeStats(register VolumeDiskData * vol)
|
|
{
|
|
VOL_LOCK;
|
|
ClearVolumeStats_r(vol);
|
|
VOL_UNLOCK;
|
|
}
|
|
|
|
void
|
|
ClearVolumeStats_r(register VolumeDiskData * vol)
|
|
{
|
|
memset(vol->weekUse, 0, sizeof(vol->weekUse));
|
|
vol->dayUse = 0;
|
|
vol->dayUseDate = 0;
|
|
}
|