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