1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <memory.h>
5 #include "ssdef.h"
6 #include "access.h"
7 
8 unsigned deaccesshead(struct VIOC *vioc,struct HEAD *head,unsigned idxblk);
9 unsigned accesshead(struct VCB *vcb,struct fiddef *fid,unsigned seg_num,
10                     struct VIOC **vioc,struct HEAD **headbuff,
11                     unsigned *retidxblk,unsigned wrtflg);
12 unsigned getwindow(struct FCB * fcb,unsigned vbn,struct VCBDEV **devptr,
13                    unsigned *phyblk,unsigned *phylen,struct fiddef *hdrfid,
14                    unsigned *hdrseq);
15 struct VCBDEV *rvn_to_dev(struct VCB *vcb,unsigned rvn);
16 
17 
18 
19 /* Bitmaps get accesses in 'WORK_UNITs' which can be an integer
20    on a little endian machine but must be a byte on a big endian system */
21 
22 #ifdef BIG_ENDIAN
23 #define WORK_UNIT unsigned char
24 #define WORK_MASK 0xff
25 #else
26 #define WORK_UNIT unsigned int
27 #define WORK_MASK 0xffffffff
28 #endif
29 #define WORK_BITS (sizeof(WORK_UNIT) * 8)
30 
31 /* update_freecount() to read the device cluster bitmap and compute
32    the number of un-used clusters */
33 
update_freecount(struct VCBDEV * vcbdev,unsigned * retcount)34 unsigned update_freecount(struct VCBDEV *vcbdev,unsigned *retcount)
35 {
36     register unsigned sts;
37     register unsigned free_clusters = 0;
38     register unsigned map_block, map_end = (vcbdev->max_cluster + 4095) / 4096 + 2;
39     for (map_block = 2; map_block < map_end; ) {
40         struct VIOC *vioc;
41         unsigned blkcount;
42         WORK_UNIT *bitmap,*work_ptr;
43         register unsigned work_count;
44         sts = accesschunk(vcbdev->mapfcb,map_block, &vioc,(char **) &bitmap,&blkcount,0);
45         if (!(sts & 1)) return sts;
46         if (blkcount > map_end - map_block) blkcount = map_end - map_block + 1;
47         work_ptr = bitmap;
48         work_count = blkcount * 512 / sizeof(WORK_UNIT);
49         do {
50             register WORK_UNIT work_val = *work_ptr++;
51             if (work_val == WORK_MASK) {
52                 free_clusters += WORK_BITS;
53             } else {
54                 while (work_val != 0) {
55                     if (work_val & 1) free_clusters++;
56                     work_val = work_val >> 1;
57                 }
58             }
59         } while (--work_count > 0);
60         sts = deaccesschunk(vioc,0,0,1);
61         if (!(sts & 1)) return sts;
62         map_block += blkcount;
63     }
64     *retcount = free_clusters;
65     return sts;
66 }
67 
68 /* bitmap_modify() will either set or release a block of bits in the
69    device cluster bitmap */
70 
bitmap_modify(struct VCBDEV * vcbdev,unsigned cluster,unsigned count,unsigned release_flag)71 unsigned bitmap_modify(struct VCBDEV *vcbdev,unsigned cluster,unsigned count,
72                        unsigned release_flag)
73 {
74     register unsigned sts;
75     register unsigned clust_count = count;
76     register unsigned map_block = cluster / 4096 + 2;
77     register unsigned block_offset = cluster % 4096;
78     if (clust_count < 1) return SS$_BADPARAM;
79     if (cluster + clust_count > vcbdev->max_cluster + 1) return SS$_BADPARAM;
80     do {
81         struct VIOC *vioc;
82         unsigned blkcount;
83         WORK_UNIT *bitmap;
84         register WORK_UNIT *work_ptr;
85         register unsigned work_count;
86         sts = accesschunk(vcbdev->mapfcb,map_block,&vioc,(char **) &bitmap,&blkcount,1);
87         if (!(sts & 1)) return sts;
88         work_ptr = bitmap + block_offset / WORK_BITS;
89         if (block_offset % WORK_BITS) {
90             register unsigned bit_no = block_offset % WORK_BITS;
91             register WORK_UNIT bit_mask = WORK_MASK;
92             if (bit_no + clust_count < WORK_BITS) {
93                 bit_mask = bit_mask >> (WORK_BITS - clust_count);
94                 clust_count = 0;
95             } else {
96                 clust_count -= WORK_BITS - bit_no;
97             }
98             bit_mask = bit_mask << bit_no;
99             if (release_flag) {
100                 *work_ptr++ |= bit_mask;
101             } else {
102                 *work_ptr++ &= ~bit_mask;
103             }
104             block_offset += WORK_BITS - bit_no;
105         }
106         work_count = (blkcount * 4096 - block_offset) / WORK_BITS;
107         if (work_count > clust_count / WORK_BITS) {
108             work_count = clust_count / WORK_BITS;
109             block_offset = 1;
110         } else {
111             block_offset = 0;
112         }
113         clust_count -= work_count * WORK_BITS;
114         if (release_flag) {
115             while (clust_count-- > 0) {
116                 *work_ptr++ = WORK_MASK;
117             }
118         } else {
119             while (work_count-- > 0) {
120                 *work_ptr++ = 0;
121             }
122         }
123         if (clust_count != 0 && block_offset) {
124             register WORK_UNIT bit_mask = WORK_MASK >> (WORK_BITS - clust_count);
125             if (release_flag) {
126                 *work_ptr++ |= bit_mask;
127             } else {
128                 *work_ptr++ &= ~bit_mask;
129             }
130             clust_count = 0;
131         }
132         sts = deaccesschunk(vioc,map_block,blkcount,1);
133         if (!(sts & 1)) return sts;
134         map_block += blkcount;
135         block_offset = 0;
136     } while (clust_count != 0);
137     return sts;
138 }
139 
140 /* bitmap_search() is a routine to find a pool of free clusters in the
141    device cluster bitmap */
142 
bitmap_search(struct VCBDEV * vcbdev,unsigned * position,unsigned * count)143 unsigned bitmap_search(struct VCBDEV *vcbdev,unsigned *position,unsigned *count)
144 {
145     register unsigned sts;
146     register unsigned map_block,block_offset;
147     register unsigned search_words,needed;
148     register unsigned run = 0,cluster;
149     register unsigned best_run = 0,best_cluster = 0;
150     needed = *count;
151     if (needed < 1 || needed > vcbdev->max_cluster + 1) return SS$_BADPARAM;
152     cluster = *position;
153     if (cluster + *count > vcbdev->max_cluster + 1) cluster = 0;
154     map_block = cluster / 4096 + 2;
155     block_offset = cluster % 4096;
156     cluster = cluster - (cluster % WORK_BITS);
157     search_words = vcbdev->max_cluster / WORK_BITS;
158     do {
159         struct VIOC *vioc;
160         unsigned blkcount;
161         WORK_UNIT *bitmap;
162         register WORK_UNIT *work_ptr, work_val;
163         register unsigned work_count;
164         sts = accesschunk(vcbdev->mapfcb,map_block,&vioc,(char **) &bitmap,&blkcount,1);
165         if ((sts & 1) == 0) return sts;
166         work_ptr = bitmap + block_offset / WORK_BITS;
167         work_val = *work_ptr++;
168         if (block_offset % WORK_BITS) {
169             work_val = work_val && (WORK_MASK << block_offset % WORK_BITS);
170         }
171         work_count = (blkcount * 4096 - block_offset) / WORK_BITS;
172         if (work_count > search_words) work_count = search_words;
173         search_words -= work_count;
174         do {
175             if (work_val == WORK_MASK) {
176                 run += WORK_BITS;
177             } else {
178                 register unsigned bit_no = 0;
179                 while (work_val != 0) {
180                     if (work_val & 1) {
181                         run++;
182                     } else {
183                         if (run > best_run) {
184                             best_run = run;
185                             best_cluster = cluster + bit_no;
186                         }
187                         run = 0;
188                     }
189                     work_val = work_val >> 1;
190                     bit_no++;
191                 }
192                 if (bit_no < WORK_BITS) {
193                     if (run > best_run) {
194                         best_run = run;
195                         best_cluster = cluster + bit_no;
196                     }
197                     run = 0;
198                 }
199             }
200             cluster += WORK_BITS;
201             if (work_count-- > 0) {
202                 work_val = *work_ptr++;
203             } else {
204                 break;
205             }
206         } while (best_run < needed);
207         deaccesschunk(vioc,map_block,0,1);
208         if ((sts & 1) == 0) break;
209         map_block += blkcount;
210         block_offset = 0;
211     } while (best_run < needed && search_words != 0);
212     if (best_run > needed) best_run = needed;
213     *count = best_run;
214     *position = best_cluster;
215     return sts;
216 }
217 
218 /* headmap_clear() will release a header from the indexf.sys file header
219    bitmap */
220 
headmap_clear(struct VCBDEV * vcbdev,unsigned head_no)221 unsigned headmap_clear(struct VCBDEV *vcbdev,unsigned head_no)
222 {
223     WORK_UNIT *bitmap;
224     struct VIOC *vioc;
225     register unsigned sts;
226     register unsigned map_block = head_no / 4096 + vcbdev->home.hm2$w_cluster * 4 + 1;
227     if (head_no < 10) return 0;
228     sts = accesschunk(vcbdev->idxfcb,map_block,&vioc,(char **) &bitmap,NULL,1);
229     if (sts & 1) {
230         bitmap[(head_no % 4096) / WORK_BITS] &= ~(1 << (head_no % WORK_BITS));
231         sts = deaccesschunk(vioc,map_block,1,1);
232     }
233     return sts;
234 }
235 
236 /* update_findhead() will locate a free header from indexf.sys */
237 
update_findhead(struct VCBDEV * vcbdev,unsigned * rethead_no,struct VIOC ** retvioc,struct HEAD ** headbuff,unsigned * retidxblk)238 unsigned update_findhead(struct VCBDEV *vcbdev,unsigned *rethead_no,
239                          struct VIOC **retvioc,struct HEAD **headbuff,
240                          unsigned *retidxblk)
241 {
242     unsigned head_no = 0;
243     register unsigned sts;
244     do {
245         struct VIOC *vioc;
246         int modify_flag = 0;
247         unsigned blkcount;
248         WORK_UNIT *bitmap,*work_ptr;
249         register unsigned map_block,work_count;
250         map_block = head_no / 4096 + vcbdev->home.hm2$w_cluster * 4 + 1;
251         sts = accesschunk(vcbdev->idxfcb,map_block,
252             &vioc,(char **) &bitmap,&blkcount,1);
253         if ((sts & 1) == 0) return sts;
254         work_count = (head_no % 4096) / WORK_BITS;
255         work_ptr = bitmap + work_count;
256         work_count = blkcount * 512 / WORK_BITS - work_count;
257         do {
258             register WORK_UNIT work_val = *work_ptr;
259             if (work_val == WORK_MASK) {
260                 head_no += WORK_BITS;
261             } else {
262                 register unsigned bit_no = 0;
263                 for (bit_no = 0; bit_no < WORK_BITS; bit_no++) {
264                     if ((work_val & (1 << bit_no)) == 0) {
265                         register unsigned idxblk = head_no +
266                             VMSWORD(vcbdev->home.hm2$w_ibmapvbn) +
267                             VMSWORD(vcbdev->home.hm2$w_ibmapsize);
268                         sts = accesschunk(vcbdev->idxfcb,idxblk,retvioc,(char **) headbuff,NULL,1);
269                         if (sts & 1) {
270                             *work_ptr |= 1 << bit_no;
271                             modify_flag = 1;
272                             if ((*headbuff)->fh2$w_checksum != 0 || (*headbuff)->fh2$w_fid.fid$w_num != 0 ||
273                                 VMSLONG((*headbuff)->fh2$l_filechar) & FH2$M_MARKDEL == 0) {
274                                 sts = deaccesschunk(*retvioc,0,0,0);
275                             } else {
276                                 *rethead_no = head_no + 1;
277                                 *retidxblk = idxblk;
278                                 deaccesschunk(vioc,map_block,blkcount,modify_flag);
279                                 return SS$_NORMAL;
280                             }
281                         }
282                     }
283                     head_no++;
284                 }
285             }
286             work_ptr++;
287         } while (--work_count != 0);
288         deaccesschunk(vioc,map_block,blkcount,modify_flag);
289         if ((sts & 1) == 0) break;
290     } while (head_no < VMSLONG(vcbdev->home.hm2$l_maxfiles));
291     return sts;
292 }
293 
update_addhead(struct VCB * vcb,char * filename,struct fiddef * back,unsigned seg_num,struct fiddef * fid,struct VIOC ** vioc,struct HEAD ** rethead,unsigned * idxblk)294 unsigned update_addhead(struct VCB *vcb,char *filename,struct fiddef *back,
295                      unsigned seg_num,struct fiddef *fid,
296                      struct VIOC **vioc,struct HEAD **rethead,
297                      unsigned *idxblk)
298 {
299     register unsigned free_space = 0;
300     register unsigned device,rvn,sts;
301     unsigned head_no;
302     struct IDENT *id;
303     struct HEAD *head;
304     struct VCBDEV *vcbdev = NULL;
305     for (device = 0; device < vcb->devices; device++) {
306         if (vcb->vcbdev[device].dev != NULL) {
307             if (vcb->vcbdev[device].free_clusters > free_space) {
308                 free_space = vcb->vcbdev[device].free_clusters;
309                 vcbdev = &vcb->vcbdev[device];
310                 rvn = device;
311             }
312         }
313     }
314     if (vcbdev == NULL) return SS$_DEVICEFULL;
315 
316     sts = update_findhead(vcbdev,&head_no,vioc,&head,idxblk);
317     if (!(sts & 1)) return sts;
318     printf("Header %d index %d rvn %d\n",head_no,idxblk,rvn);
319     fid->fid$w_num = head_no;
320     fid->fid$w_seq = ++head->fh2$w_fid.fid$w_seq;
321     if (fid->fid$w_seq == 0) fid->fid$w_seq = 1;
322     if (rvn > 0) {
323         fid->fid$b_rvn = rvn + 1;
324     } else {
325         fid->fid$b_rvn = 0;
326     }
327     fid->fid$b_nmx = head_no >> 16;
328     memset(head,0,512);
329     head->fh2$b_idoffset = 40;
330     head->fh2$b_mpoffset = 100;
331     head->fh2$b_acoffset = 255;
332     head->fh2$b_rsoffset = 255;
333     head->fh2$w_seg_num = seg_num;
334     head->fh2$w_struclev = 513;
335     head->fh2$l_fileowner.uic$w_mem = 4;
336     head->fh2$l_fileowner.uic$w_grp = 1;
337     fid_copy(&head->fh2$w_fid,fid,0);
338     if (back != NULL) fid_copy(&head->fh2$w_backlink,back,0);
339     id = (struct IDENT *) ((unsigned short *) head + 40);
340     memset(id->fi2$t_filenamext,' ',66);
341     if (strlen(filename) < 20) {
342         memset(id->fi2$t_filename,' ',20);
343         memcpy(id->fi2$t_filename,filename,strlen(filename));
344     } else {
345         memcpy(id->fi2$t_filename,filename,20);
346         memcpy(id->fi2$t_filenamext,filename+20,strlen(filename+20));
347     }
348     id->fi2$w_revision = 1;
349     sys_gettim(id->fi2$q_credate);
350     memcpy(id->fi2$q_revdate,id->fi2$q_credate,sizeof(id->fi2$q_credate));
351     memcpy(id->fi2$q_expdate,id->fi2$q_credate,sizeof(id->fi2$q_credate));
352     head->fh2$w_recattr.fat$l_efblk = VMSSWAP(1);
353     {
354         unsigned short check = checksum((vmsword *) head);
355         head->fh2$w_checksum = VMSWORD(check);
356     }
357     return 1;
358 }
359 
360 /* update_create() will create a new file... */
361 
update_create(struct VCB * vcb,struct fiddef * did,char * filename,struct fiddef * fid,struct FCB ** fcb)362 unsigned update_create(struct VCB *vcb,struct fiddef *did,char *filename,
363                        struct fiddef *fid,struct FCB **fcb)
364 {
365     struct VIOC *vioc;
366     struct HEAD *head;
367     unsigned idxblk;
368     register unsigned sts;
369     sts = update_addhead(vcb,filename,did,0,fid,&vioc,&head,&idxblk);
370     if (!(sts & 1)) return sts;
371     sts = deaccesshead(vioc,head,idxblk);
372     if (sts & 1 && fcb != NULL) {
373         sts = accessfile(vcb,fid,fcb,1);
374     }
375     printf("(%d,%d,%d) %d\n",fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn,sts);
376     return sts;
377 }
378 
update_extend(struct FCB * fcb,unsigned blocks,unsigned contig)379 unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig)
380 {
381     register unsigned sts;
382     struct VCBDEV *vcbdev;
383     struct VIOC *vioc;
384     struct HEAD *head;
385     unsigned headvbn;
386     struct fiddef hdrfid;
387     unsigned hdrseq;
388     unsigned start_pos = 0;
389     unsigned block_count = blocks;
390     if (block_count < 1) return 0;
391     if ((fcb->status & FCB_WRITE) == 0) return SS$_WRITLCK;
392     if (fcb->hiblock > 0) {
393         unsigned mapblk,maplen;
394         sts = getwindow(fcb,fcb->hiblock,&vcbdev,&mapblk,&maplen,&hdrfid,&hdrseq);
395         if ((sts & 1) == 0) return sts;
396         start_pos = mapblk + 1;
397         if (hdrseq != 0) {
398             sts = accesshead(fcb->vcb,&hdrfid,hdrseq,&vioc,&head,&headvbn,1);
399             if ((sts & 1) == 0) return sts;
400         } else {
401             head = fcb->head;
402             vioc = NULL;
403         }
404     } else {
405         head = fcb->head;
406         vioc = NULL;
407         start_pos = 0;          /* filenum * 3 /indexfsize * volumesize; */
408     }
409     if (vioc == NULL) vcbdev = rvn_to_dev(fcb->vcb,fcb->rvn);
410     if (vcbdev->free_clusters == 0 || head->fh2$b_map_inuse + 4 >=
411                 head->fh2$b_acoffset - head->fh2$b_mpoffset) {
412         struct VIOC *nvioc;
413         struct HEAD *nhead;
414         unsigned nidxblk;
415         sts = update_addhead(fcb->vcb,"",&head->fh2$w_fid,head->fh2$w_seg_num+1,
416               &head->fh2$w_ext_fid,&nvioc,&nhead,&nidxblk);
417         if (!(sts & 1)) return sts;
418         if (vioc != NULL) deaccesshead(vioc,head,headvbn);
419         vioc = nvioc;
420         head = nhead;
421         headvbn = nidxblk;
422         vcbdev = rvn_to_dev(fcb->vcb,head->fh2$w_fid.fid$b_rvn);
423     }
424     sts = bitmap_search(vcbdev,&start_pos,&block_count);
425     printf("Update_extend %d %d\n",start_pos,block_count);
426     if (sts & 1) {
427         if (block_count < 1 || contig && block_count * vcbdev->clustersize < blocks) {
428             sts = SS$_DEVICEFULL;
429         } else {
430             register unsigned short *mp;
431             mp = (unsigned short *) head + head->fh2$b_mpoffset + head->fh2$b_map_inuse;
432             *mp++ = (3 << 14) | ((block_count *vcbdev->clustersize - 1) >> 16);
433             *mp++ = (block_count * vcbdev->clustersize - 1) & 0xffff;
434             *mp++ = (start_pos * vcbdev->clustersize) & 0xffff;
435             *mp++ = (start_pos * vcbdev->clustersize) >> 16;
436             head->fh2$b_map_inuse += 4;
437             fcb->hiblock += block_count * vcbdev->clustersize;
438             fcb->head->fh2$w_recattr.fat$l_hiblk = VMSSWAP(fcb->hiblock * vcbdev->clustersize);
439             sts = bitmap_modify(vcbdev,start_pos,block_count,0);
440         }
441     }
442     if (vioc != NULL) deaccesshead(vioc,head,headvbn);
443     return sts;
444 }
445 
446 
447 
448 
449 /* This routine has bugs and does NOT work properly yet!!!!
450 It may be something simple but I haven't had time to look...
451 So DON'T use mount/write!!!  */
452 
deallocfile(struct FCB * fcb)453 unsigned deallocfile(struct FCB *fcb)
454 {
455     register unsigned sts = 1;
456     /*
457     First mark all file clusters as free in BITMAP.SYS
458     */
459     register unsigned vbn = 1;
460     while (vbn <= fcb->hiblock) {
461         register unsigned sts;
462         unsigned phyblk,phylen;
463         struct VCBDEV *vcbdev;
464         sts = getwindow(fcb,vbn,&vcbdev,&phyblk,&phylen,NULL,NULL);
465         if ((sts & 1) == 0) break;
466 
467         sts = bitmap_modify(vcbdev,phyblk,phylen,1);
468         if ((sts & 1) == 0) break;
469     }
470     /*
471     Now reset file header bit map in INDEXF.SYS and
472     update each of the file headers...
473     */
474     {
475         unsigned rvn = fcb->rvn;
476         unsigned headvbn = fcb->headvbn;
477         struct HEAD *head = fcb->head;
478         struct VIOC *headvioc = fcb->headvioc;
479         do {
480             unsigned ext_seg_num = 0;
481             struct fiddef extfid;
482             register struct VCBDEV *vcbdev;
483             unsigned *bitmap;
484             struct VIOC *vioc;
485             register unsigned filenum = (head->fh2$w_fid.fid$b_nmx << 16) +
486                 head->fh2$w_fid.fid$w_num - 1;
487             register unsigned idxblk;
488             vcbdev = rvn_to_dev(fcb->vcb,rvn);
489             if (vcbdev == NULL) break;
490             idxblk = filenum / 4096 +
491                 vcbdev->home.hm2$w_cluster * 4 + 1;
492             sts = accesschunk(vcbdev->idxfcb,idxblk,&vioc,
493                 (char **) &bitmap,NULL,1);
494             if (sts & 1) {
495                 bitmap[(filenum % 4096) / WORK_BITS] &=
496                     ~(1 << (filenum % WORK_BITS));
497                 sts = deaccesschunk(vioc,idxblk,1,1);
498             } else {
499                 break;
500             }
501             head->fh2$w_fid.fid$w_num = 0;
502             head->fh2$w_fid.fid$b_rvn = 0;
503             head->fh2$w_fid.fid$b_nmx = 0;
504             head->fh2$w_checksum = 0;
505             ext_seg_num++;
506             memcpy(&extfid,&fcb->head->fh2$w_ext_fid,sizeof(struct fiddef));
507             sts = deaccesshead(headvioc,NULL,headvbn);
508             if ((sts & 1) == 0) break;
509             if (extfid.fid$b_rvn == 0) {
510                 extfid.fid$b_rvn = rvn;
511             } else {
512                 rvn = extfid.fid$b_rvn;
513             }
514             if (extfid.fid$w_num != 0 || extfid.fid$b_nmx != 0) {
515                 sts = accesshead(fcb->vcb,&extfid,ext_seg_num,&headvioc,&head,&headvbn,1);
516                 if ((sts & 1) == 0) break;
517             } else {
518                 break;
519             }
520         } while (1);
521         if (sts & 1) {
522             fcb->headvioc = NULL;
523             cache_untouch(&fcb->cache,0);
524             cache_delete(&fcb->cache);
525         }
526     }
527     return sts;
528 }
529 
530 
531 
532 /* accesserase: delete a file... */
533 
accesserase(struct VCB * vcb,struct fiddef * fid)534 unsigned accesserase(struct VCB * vcb,struct fiddef * fid)
535 {
536     struct FCB *fcb;
537     register int sts;
538     sts = accessfile(vcb,fid,&fcb,1);
539     if (sts & 1) {
540         fcb->head->fh2$l_filechar |= FH2$M_MARKDEL;
541         printf("Accesserase ... \n");
542         sts = deaccessfile(fcb);
543     }
544     return sts;
545 }
546 
547 
548 
549 
550 #ifdef EXTEND
extend(struct FCB * fcb,unsigned blocks)551 unsigned extend(struct FCB *fcb,unsigned blocks)
552 {
553     register unsigned sts;
554     struct VCBDEV *vcbdev;
555     unsigned clusterno;
556     unsigned extended = 0;
557     if ((fcb->status & FCB_WRITE) == 0) return SS$_WRITLCK;
558     if (fcb->hiblock > 0) {
559         unsigned phyblk,phylen;
560         sts = getwindow(fcb,fcb->hiblock,&vcbdev,&phyblk,&phylen,NULL,NULL);
561         clusterno = (phyblk + 1) / vcbdev->home.hm2$w_cluster;
562         if ((sts & 1) == 0) return sts;
563     } else {
564         vcbdev = fcb->vcb->vcbdev;
565         clusterno = 0;          /* filenum * 3 /indexfsize * volumesize; */
566     }
567     while (extended < blocks) {
568         unsigned *bitmap,blkcount;
569         struct VIOC *vioc;
570         register unsigned clustalq = 0;
571         register unsigned clustersz = vcbdev->home.hm2$w_cluster;
572         sts = accesschunk(vcbdev->mapfcb,clusterno / 4096 + 2,
573             &vioc,(char **) &bitmap,&blkcount,1);
574         if ((sts & 1) == 0) return sts;
575         do {
576             register unsigned wordno = (clusterno % 4096) / WORK_BITS;
577             register unsigned wordval = bitmap[wordno];
578             if (wordval == 0xffff) {
579                 if (clustalq) break;
580                 clusterno = (clusterno % WORK_BITS) *
581                     WORK_BITS + 1;
582             } else {
583                 register unsigned bitno = clusterno % WORK_BITS;
584                 do {
585                     if (wordval & (1 << bitno)) {
586                         if (clustalq) break;
587                     } else {
588                         clustalq++;
589                         wordval |= 1 << bitno;
590                     }
591                     clusterno++;
592                     if (clustalq >= (extended - blocks)) break;
593                 } while (++bitno < WORK_BITS);
594                 if (clustalq) {
595                     bitmap[wordno] = wordval;
596                     if (bitno < WORK_BITS) break;
597                 }
598             }
599         } while (++wordno < blkcount * 512 / sizeof(unsigned));
600         mp = (unsigned word *) fcb->head + fcb->head->fh2$b_mpoffset;
601         *mp++ = (3 << 14) | (clustalq >> 16);
602         *mp++ = clustalq & 0xff;
603         *mp++ = clustno & 0xff;
604         *clusertize
605             * mp++ = clustno << 16;
606         fcb->head->fh2$b_map_inuse + 4;
607         fcb->hiblock += clustalq;
608         fcb->head.fh2$w_recattr.fat$l_hiblk[0] = fcb->hiblock >> 16;
609         fcb->head.fh2$w_recattr.fat$l_hiblk[1] = fcb->hiblock & 0xff;
610         sts = deaccesschunk(vioc,clusterno / 4096 + 2,blkcount,1);
611         /* code to append clusterno:clustalq to map */
612     }
613 }
614 #endif
615 
616 
617 
618 #ifdef EXTEND
619 
access_create(struct VCB * vcb,struct FCB ** fcbadd,unsigned blocks)620 unsigned access_create(struct VCB * vcb,struct FCB ** fcbadd,unsigned blocks) {
621     register struct FCB *fcb;
622     struct fiddef fid;
623     unsigned create = sizeof(struct FCB);
624     if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK;
625 
626     sts = headmap_search(struct VCBDEV * vcbdev,struct fiddef * fid,
627         struct VIOC ** vioc,struct HEAD ** headbuff,unsigned *retidxblk,) {
628         fcb = cachesearch((void *) &vcb->fcb,filenum,0,NULL,NULL,&create);
629         if (fcb == NULL) return SS$_INSFMEM;
630         /* If not found make one... */
631         if (create == 0) {
632             fcb->cache.objtype = CACHETYPE_DEV;
633             fcb->rvn = fid->fid_b_rvn;
634             if (fcb->rvn == 0 && vcb->devices > 1) fcb->rvn = 1;
635             fcb->vcb = vcb;
636             fcb->wcb = NULL;
637             fcb->headvbn = 0;
638             fcb->vioc = NULL;
639             fcb->headvioc = NULL;
640             fcb->cache.objmanager = fcbmanager;
641         }
642         if (wrtflg) {
643             if (fcb->headvioc != NULL && (fcb->cache.status & CACHE_WRITE) == 0) {
644                 deaccesshead(fcb->headvioc,NULL,0);
645                 fcb->headvioc = NULL;
646             }
647             fcb->cache.status |= CACHE_WRITE;
648         }
649         if (fcb->headvioc == NULL) {
650             register unsigned sts;
651             if (vcb->idxboot != NULL) {
652                 *fcbadd = fcb;
653                 fcb->hiblock = 32767;   /* guess at indexf.sys file size */
654                 fcb->highwater = 0;
655                 fcb->head = vcb->idxboot;       /* Load bootup header */
656             }
657             sts = accesshead(vcb,fid,0,&fcb->headvioc,&fcb->head,&fcb->headvbn,wrtflg);
658             if (sts & 1) {
659                 fcb->hiblock = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_hiblk);
660                 if (fcb->head->fh2$b_idoffset > 39) {
661                     fcb->highwater = fcb->head->fh2$l_highwater;
662                 } else {
663                     fcb->highwater = 0;
664                 }
665             } else {
666                 printf("Accessfile status %d\n",sts);
667                 fcb->cache.objmanager = NULL;
668                 cacheuntouch(&fcb->cache,0,0);
669                 cachefree(&fcb->cache);
670                 return sts;
671             }
672         }
673         *fcbadd = fcb;
674         return SS$_NORMAL;
675     }
676 #endif
677 
678