Tidy the vol directory
[openafs.git] / src / vol / vutil.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11         System:         VICE-TWO
12         Module:         vutil.c
13         Institution:    The Information Technology Center, Carnegie-Mellon University
14
15  */
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <errno.h>
24 #ifdef AFS_NT40_ENV
25 #include <time.h>
26 #include <fcntl.h>
27 #else
28 #include <sys/time.h>
29 #include <sys/file.h>
30 #include <unistd.h>
31 #endif
32 #include <sys/stat.h>
33 #ifdef AFS_PTHREAD_ENV
34 #include <assert.h>
35 #else /* AFS_PTHREAD_ENV */
36 #include <afs/assert.h>
37 #endif /* AFS_PTHREAD_ENV */
38
39 #include <rx/xdr.h>
40 #include <afs/afsint.h>
41 #include "nfs.h"
42 #include <afs/errors.h>
43 #include "lock.h"
44 #include "lwp.h"
45 #include <afs/afssyscalls.h>
46 #include "ihandle.h"
47 #include <afs/afsutil.h>
48 #ifdef AFS_NT40_ENV
49 #include "ntops.h"
50 #include <io.h>
51 #endif
52 #include "vnode.h"
53 #include "volume.h"
54 #include "partition.h"
55 #include "viceinode.h"
56
57 #include "volinodes.h"
58 #include "vol_prototypes.h"
59
60 #ifdef  AFS_AIX_ENV
61 #include <sys/lockf.h>
62 #endif
63 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
64 #include <string.h>
65 #else
66 #include <strings.h>
67 #endif
68
69 #ifdef O_LARGEFILE
70 #define afs_open        open64
71 #else /* !O_LARGEFILE */
72 #define afs_open        open
73 #endif /* !O_LARGEFILE */
74
75 /*@printflike@*/ extern void Log(const char *format, ...);
76
77 #define nFILES  (sizeof (stuff)/sizeof(struct stuff))
78
79 /* Note:  the volume creation functions herein leave the destroyMe flag in the
80    volume header ON:  this means that the volumes will not be attached by the
81    file server and WILL BE DESTROYED the next time a system salvage is performed */
82
83 static void
84 RemoveInodes(Device dev, VolumeId vid)
85 {
86     register int i;
87     IHandle_t *handle;
88
89     /* This relies on the fact that IDEC only needs the device and NT only
90      * needs the dev and vid to decrement volume special files.
91      */
92     IH_INIT(handle, dev, vid, -1);
93     for (i = 0; i < nFILES; i++) {
94         Inode inode = *stuff[i].inode;
95         if (VALID_INO(inode))
96             IH_DEC(handle, inode, vid);
97     }
98     IH_RELEASE(handle);
99 }
100
101 Volume *
102 VCreateVolume(Error * ec, char *partname, VolId volumeId, VolId parentId)
103 {                               /* Should be the same as volumeId if there is
104                                  * no parent */
105     Volume *retVal;
106     VOL_LOCK;
107     retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
108     VOL_UNLOCK;
109     return retVal;
110 }
111
112 Volume *
113 VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId)
114 {                               /* Should be the same as volumeId if there is
115                                  * no parent */
116     VolumeDiskData vol;
117     int fd, i;
118     char headerName[32], volumePath[64];
119     Device device;
120     struct DiskPartition64 *partition;
121     struct VolumeDiskHeader diskHeader;
122     IHandle_t *handle;
123     FdHandle_t *fdP;
124     Inode nearInode = 0;
125     char *part, *name;
126
127     *ec = 0;
128     memset(&vol, 0, sizeof(vol));
129     vol.id = volumeId;
130     vol.parentId = parentId;
131     vol.copyDate = time(0);     /* The only date which really means when this
132                                  * @i(instance) of this volume was created.
133                                  * Creation date does not mean this */
134
135     /* Initialize handle for error case below. */
136     handle = NULL;
137
138     /* Verify that the parition is valid before writing to it. */
139     if (!(partition = VGetPartition_r(partname, 0))) {
140         Log("VCreateVolume: partition %s is not in service.\n", partname);
141         *ec = VNOVOL;
142         return NULL;
143     }
144 #if     defined(NEARINODE_HINT)
145     nearInodeHash(volumeId, nearInode);
146     nearInode %= partition->f_files;
147 #endif
148     VGetVolumePath(ec, vol.id, &part, &name);
149     if (*ec == VNOVOL || !strcmp(partition->name, part)) {
150         /* this case is ok */
151     } else {
152         /* return EXDEV if it's a clone to an alternate partition
153          * otherwise assume it's a move */
154         if (vol.parentId != vol.id) {
155             *ec = EXDEV;
156             return NULL;
157         }
158     }
159     VLockPartition_r(partname);
160     memset(&tempHeader, 0, sizeof(tempHeader));
161     tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
162     tempHeader.stamp.version = VOLUMEHEADERVERSION;
163     tempHeader.id = vol.id;
164     tempHeader.parent = vol.parentId;
165     vol.stamp.magic = VOLUMEINFOMAGIC;
166     vol.stamp.version = VOLUMEINFOVERSION;
167     vol.destroyMe = DESTROY_ME;
168     (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_cast_uint32(vol.id));
169     (void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s",
170                        VPartitionPath(partition), headerName);
171     fd = afs_open(volumePath, O_CREAT | O_EXCL | O_WRONLY, 0600);
172     if (fd == -1) {
173         if (errno == EEXIST) {
174             Log("VCreateVolume: Header file %s already exists!\n",
175                 volumePath);
176             *ec = VVOLEXISTS;
177         } else {
178             Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
179             *ec = VNOVOL;
180         }
181         return NULL;
182     }
183     device = partition->device;
184
185     for (i = 0; i < nFILES; i++) {
186         register struct stuff *p = &stuff[i];
187         if (p->obsolete)
188             continue;
189 #ifdef AFS_NAMEI_ENV
190         *(p->inode) =
191             IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
192                       (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
193                       INODESPECIAL, p->inodeType, vol.parentId);
194         if (!(VALID_INO(*(p->inode)))) {
195             if (errno == EEXIST) {
196                 /* Increment the reference count instead. */
197                 IHandle_t *lh;
198                 int code;
199
200 #ifdef AFS_NT40_ENV
201                 *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
202 #else
203                 *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
204 #endif
205                 IH_INIT(lh, device, parentId, *(p->inode));
206                 fdP = IH_OPEN(lh);
207                 if (fdP == NULL) {
208                     IH_RELEASE(lh);
209                     goto bad;
210                 }
211                 code = IH_INC(lh, *(p->inode), parentId);
212                 FDH_REALLYCLOSE(fdP);
213                 IH_RELEASE(lh);
214                 if (code < 0)
215                     goto bad;
216                 continue;
217             }
218         }
219 #else
220         *(p->inode) =
221             IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
222                       vol.id, INODESPECIAL, p->inodeType, vol.parentId);
223 #endif
224
225         if (!VALID_INO(*(p->inode))) {
226             Log("VCreateVolume:  Problem creating %s file associated with volume header %s\n", p->description, volumePath);
227           bad:
228             if (handle)
229                 IH_RELEASE(handle);
230             RemoveInodes(device, vol.id);
231             *ec = VNOVOL;
232             close(fd);
233             return NULL;
234         }
235         IH_INIT(handle, device, vol.parentId, *(p->inode));
236         fdP = IH_OPEN(handle);
237         if (fdP == NULL) {
238             Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
239                 PrintInode(NULL, *(p->inode)), errno);
240             goto bad;
241         }
242         if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
243             Log("VCreateVolume:  Problem lseek inode %s (err=%d)\n",
244                 PrintInode(NULL, *(p->inode)), errno);
245             FDH_REALLYCLOSE(fdP);
246             goto bad;
247         }
248         if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) !=
249             sizeof(p->stamp)) {
250             Log("VCreateVolume:  Problem writing to  inode %s (err=%d)\n",
251                 PrintInode(NULL, *(p->inode)), errno);
252             FDH_REALLYCLOSE(fdP);
253             goto bad;
254         }
255         FDH_REALLYCLOSE(fdP);
256         IH_RELEASE(handle);
257         nearInode = *(p->inode);
258     }
259
260     IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
261     fdP = IH_OPEN(handle);
262     if (fdP == NULL) {
263         Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
264             PrintInode(NULL, tempHeader.volumeInfo), errno);
265         unlink(volumePath);
266         goto bad;
267     }
268     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
269         Log("VCreateVolume:  Problem lseek inode %s (err=%d)\n",
270             PrintInode(NULL, tempHeader.volumeInfo), errno);
271         FDH_REALLYCLOSE(fdP);
272         unlink(volumePath);
273         goto bad;
274     }
275     if (FDH_WRITE(fdP, (char *)&vol, sizeof(vol)) != sizeof(vol)) {
276         Log("VCreateVolume:  Problem writing to  inode %s (err=%d)\n",
277             PrintInode(NULL, tempHeader.volumeInfo), errno);
278         FDH_REALLYCLOSE(fdP);
279         unlink(volumePath);
280         goto bad;
281     }
282     FDH_CLOSE(fdP);
283     IH_RELEASE(handle);
284
285     VolumeHeaderToDisk(&diskHeader, &tempHeader);
286     if (write(fd, &diskHeader, sizeof(diskHeader)) != sizeof(diskHeader)) {
287         Log("VCreateVolume: Unable to write volume header %s; volume %u not created\n", volumePath, vol.id);
288         unlink(volumePath);
289         goto bad;
290     }
291     fsync(fd);
292     close(fd);
293     return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY));
294 }
295
296
297 void
298 AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext)
299 {
300     VOL_LOCK;
301     AssignVolumeName_r(vol, name, ext);
302     VOL_UNLOCK;
303 }
304
305 void
306 AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext)
307 {
308     register char *dot;
309     strncpy(vol->name, name, VNAMESIZE - 1);
310     vol->name[VNAMESIZE - 1] = '\0';
311     dot = strrchr(vol->name, '.');
312     if (dot && (strcmp(dot, ".backup") == 0 || strcmp(dot, ".readonly") == 0))
313         *dot = 0;
314     if (ext)
315         strncat(vol->name, ext, VNAMESIZE - 1 - strlen(vol->name));
316 }
317
318 afs_int32
319 CopyVolumeHeader_r(VolumeDiskData * from, VolumeDiskData * to)
320 {
321     /* The id and parentId fields are not copied; these are inviolate--the to volume
322      * is assumed to have already been created.  The id's cannot be changed once
323      * creation has taken place, since they are embedded in the various inodes associated
324      * with the volume.  The copydate is also inviolate--it always reflects the time
325      * this volume was created (compare with the creation date--the creation date of
326      * a backup volume is the creation date of the original parent, because the backup
327      * is used to backup the parent volume). */
328     Date copydate;
329     VolumeId id, parent;
330     id = to->id;
331     parent = to->parentId;
332     copydate = to->copyDate;
333     memcpy(to, from, sizeof(*from));
334     to->id = id;
335     to->parentId = parent;
336     to->copyDate = copydate;
337     to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
338     to->stamp.magic = VOLUMEINFOMAGIC;
339     to->stamp.version = VOLUMEINFOVERSION;
340     return 0;
341 }
342
343 afs_int32
344 CopyVolumeHeader(VolumeDiskData * from, VolumeDiskData * to)
345 {
346     afs_int32 code;
347
348     VOL_LOCK;
349     code = CopyVolumeHeader_r(from, to);
350     VOL_UNLOCK;
351     return (code);
352 }
353
354 void
355 ClearVolumeStats(register VolumeDiskData * vol)
356 {
357     VOL_LOCK;
358     ClearVolumeStats_r(vol);
359     VOL_UNLOCK;
360 }
361
362 void
363 ClearVolumeStats_r(register VolumeDiskData * vol)
364 {
365     memset(vol->weekUse, 0, sizeof(vol->weekUse));
366     vol->dayUse = 0;
367     vol->dayUseDate = 0;
368 }