unsigned char mu_cre_file(void) { unsigned char *inadr[2], *c, exit_stat; enum db_acc_method temp_acc_meth; uint4 lcnt, retadr[2]; int4 blk_init_size, initial_alq, free_blocks; gtm_uint64_t free_blocks_ll, blocks_for_extension; char buff[GLO_NAME_MAXLEN], fn_buff[MAX_FN_LEN]; unsigned int status; int free_space; struct FAB *fcb; struct NAM nam; gds_file_id new_id; io_status_block_disk iosb; char node[16]; short len; struct { short blen; short code; char *buf; short *len; int4 terminator; } item = {15, SYI$_NODENAME, &node, &len, 0}; $DESCRIPTOR(desc, buff); exit_stat = EXIT_NRM; /* The following calculations should duplicate the BT_SIZE macro from GDSBT and the LOCK_BLOCK macro from GDSFHEAD.H, * but without using a sgmnt_data which is not yet set up at this point */ #ifdef GT_CX_DEF /* This section needs serious chnages for the fileheader changes in V5 if it is ever resurrected */ over_head = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT + (WC_MAX_BUFFS + getprime(WC_MAX_BUFFS) + 1) * SIZEOF(bt_rec), DISK_BLOCK_SIZE); if (gv_cur_region->dyn.addr->acc_meth == dba_bg) { free_space = over_head - DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT + (gv_cur_region->dyn.addr->global_buffers + getprime(gv_cur_region->dyn.addr->global_buffers) + 1) * SIZEOF(bt_rec), DISK_BLOCK_SIZE); over_head += gv_cur_region->dyn.addr->lock_space ? gv_cur_region->dyn.addr->lock_space : DEF_LOCK_SIZE / OS_PAGELET_SIZE; } else if (gv_cur_region->dyn.addr->acc_meth == dba_mm) { free_space = over_head - DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE); if (gv_cur_region->dyn.addr->lock_space) { over_head += gv_cur_region->dyn.addr->lock_space; free_space += gv_cur_region->dyn.addr->lock_space; } else { over_head += DEF_LOCK_SIZE / OS_PAGELET_SIZE; free_space += DEF_LOCK_SIZE / OS_PAGELET_SIZE; } } free_space *= DISK_BLOCK_SIZE; #else assert(START_VBN_CURRENT > DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE)); free_space = ((START_VBN_CURRENT - 1) * DISK_BLOCK_SIZE) - SIZEOF_FILE_HDR_DFLT; #endif switch (gv_cur_region->dyn.addr->acc_meth) { case dba_bg: case dba_mm: mu_cre_vms_structs(gv_cur_region); fcb = ((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fab; cs_addrs = &((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->s_addrs; fcb->fab$b_shr &= FAB$M_NIL; /* No access to this file while it is created */ fcb->fab$l_nam = &nam; nam = cc$rms_nam; /* There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks * and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this * manner as every non-bitmap block must have an associated bitmap) */ fcb->fab$l_alq += DIVIDE_ROUND_UP(fcb->fab$l_alq, BLKS_PER_LMAP - 1); /* Bitmaps */ blk_init_size = fcb->fab$l_alq; fcb->fab$l_alq *= BLK_SIZE / DISK_BLOCK_SIZE; fcb->fab$l_alq += START_VBN_CURRENT - 1; initial_alq = fcb->fab$l_alq; fcb->fab$w_mrs = 512; /* no longer a relevent field to us */ break; case dba_usr: util_out_print("Database file for region !AD not created; access method is not GDS.", TRUE, REG_LEN_STR(gv_cur_region)); return EXIT_WRN; default: gtm_putmsg(VARLSTCNT(1) ERR_BADACCMTHD); return EXIT_ERR; } nam.nam$b_ess = SIZEOF(fn_buff); nam.nam$l_esa = fn_buff; nam.nam$b_nop |= NAM$M_SYNCHK; status = sys$parse(fcb, 0, 0); if (RMS$_NORMAL != status) { gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0); return EXIT_ERR; } if (nam.nam$b_node != 0) { status = sys$getsyiw(EFN$C_ENF, 0, 0, &item, &iosb, 0, 0); if (SS$_NORMAL == status) status = iosb.cond; if (SS$_NORMAL == status) { if (len == nam.nam$b_node-2 && !memcmp(nam.nam$l_esa, node, len)) { fcb->fab$l_fna = nam.nam$l_esa + nam.nam$b_node; fcb->fab$b_fns = nam.nam$b_esl - nam.nam$b_node; } } else { util_out_print("Could not get node for !AD.", TRUE, REG_LEN_STR(gv_cur_region)); exit_stat = EXIT_WRN; } } assert(gv_cur_region->dyn.addr->acc_meth == dba_bg || gv_cur_region->dyn.addr->acc_meth == dba_mm); nam.nam$l_esa = NULL; nam.nam$b_esl = 0; status = sys$create(fcb); if (status != RMS$_CREATED && status != RMS$_FILEPURGED) { switch(status) { case RMS$_FLK: util_out_print("Database file for region !AD not created; currently locked by another user.", TRUE, REG_LEN_STR(gv_cur_region)); exit_stat = EXIT_INF; break; case RMS$_NORMAL: util_out_print("Database file for region !AD not created; already exists.", TRUE, REG_LEN_STR(gv_cur_region)); exit_stat = EXIT_INF; break; case RMS$_SUPPORT: util_out_print("Database file for region !AD not created; cannot create across network.", TRUE, REG_LEN_STR(gv_cur_region)); exit_stat = EXIT_WRN; break; case RMS$_FUL: send_msg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0); /* intentionally falling through */ default: gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0); exit_stat = EXIT_ERR; } sys$dassgn(fcb->fab$l_stv); return exit_stat; } memcpy(new_id.dvi, nam.nam$t_dvi, SIZEOF(nam.nam$t_dvi)); memcpy(new_id.did, nam.nam$w_did, SIZEOF(nam.nam$w_did)); memcpy(new_id.fid, nam.nam$w_fid, SIZEOF(nam.nam$w_fid)); global_name("GT$S", &new_id, buff); /* 2nd parm is actually a gds_file_id * in global_name */ desc.dsc$w_length = buff[0]; /* By definition, a gds_file_id is dvi,fid,did from nam */ desc.dsc$a_pointer = &buff[1]; cs_addrs->db_addrs[0] = cs_addrs->db_addrs[1] = inadr[0] = inadr[1] = inadr; /* used to determine p0 or p1 allocation */ status = init_sec(cs_addrs->db_addrs, &desc, fcb->fab$l_stv, (START_VBN_CURRENT - 1), SEC$M_DZRO|SEC$M_GBL|SEC$M_WRT|SEC$M_EXPREG); if ((SS$_CREATED != status) && (SS$_NORMAL != status)) { gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0); sys$dassgn(fcb->fab$l_stv); return EXIT_ERR; } cs_data = (sgmnt_data *)cs_addrs->db_addrs[0]; memset(cs_data, 0, SIZEOF_FILE_HDR_DFLT); cs_data->createinprogress = TRUE; cs_data->trans_hist.total_blks = (initial_alq - (START_VBN_CURRENT - 1)) / (BLK_SIZE / DISK_BLOCK_SIZE); /* assert that total_blks stored in file-header = non-bitmap blocks (initial allocation) + bitmap blocks */ assert(cs_data->trans_hist.total_blks == gv_cur_region->dyn.addr->allocation + DIVIDE_ROUND_UP(gv_cur_region->dyn.addr->allocation, BLKS_PER_LMAP - 1)); cs_data->start_vbn = START_VBN_CURRENT; temp_acc_meth = gv_cur_region->dyn.addr->acc_meth; cs_data->acc_meth = gv_cur_region->dyn.addr->acc_meth = dba_bg; cs_data->extension_size = gv_cur_region->dyn.addr->ext_blk_count; mucregini(blk_init_size); cs_addrs->hdr->free_space = free_space; #ifndef GT_CX_DEF cs_addrs->hdr->unbacked_cache = TRUE; #endif cs_data->acc_meth = gv_cur_region->dyn.addr->acc_meth = temp_acc_meth; cs_data->createinprogress = FALSE; if (SS$_NORMAL == (status = disk_block_available(fcb->fab$l_stv, &free_blocks))) { blocks_for_extension = (cs_data->blk_size / DISK_BLOCK_SIZE * (DIVIDE_ROUND_UP(EXTEND_WARNING_FACTOR * (gtm_uint64_t)cs_data->extension_size, BLKS_PER_LMAP - 1) + EXTEND_WARNING_FACTOR * (gtm_uint64_t)cs_data->extension_size)); if ((gtm_uint64_t)free_blocks < blocks_for_extension) { free_blocks_ll = (gtm_uint64_t)free_blocks; gtm_putmsg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, fcb->fab$b_fns, fcb->fab$l_fna, EXTEND_WARNING_FACTOR, &blocks_for_extension, DISK_BLOCK_SIZE, &free_blocks_ll); send_msg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, fcb->fab$b_fns, fcb->fab$l_fna, EXTEND_WARNING_FACTOR, &blocks_for_extension, DISK_BLOCK_SIZE, &free_blocks_ll); } } if (SS$_NORMAL == (status = sys$updsec(((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->s_addrs.db_addrs, NULL, PSL$C_USER, 0, efn_immed_wait, &iosb, NULL, 0))) { status = sys$synch(efn_immed_wait, &iosb); if (SS$_NORMAL == status) status = iosb.cond; } else if (SS$_NOTMODIFIED == status) status = SS$_NORMAL; if (SS$_NORMAL == status) status = del_sec(SEC$M_GBL, &desc, 0); if (SS$_NORMAL == status) status = sys$deltva(cs_addrs->db_addrs, retadr, PSL$C_USER); if (SS$_NORMAL == status) status = sys$dassgn(fcb->fab$l_stv); if (SS$_NORMAL == status) { util_out_print("Database file for region !AD created.", TRUE, REG_LEN_STR(gv_cur_region)); /* the open and close are an attempt to ensure that the file is available, not under the control of an ACP, * before MUPIP exits */ fcb->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI; fcb->fab$l_fop = 0; for (lcnt = 1; (60 * MAX_OPEN_RETRY) >= lcnt; lcnt++) { /* per VMS engineering a delay is expected. We will wait up to an hour as a * Delete Global Section operation is essentially and inherently asynchronous in nature * and could take an arbitrary amount of time. */ if (RMS$_FLK != (status = sys$open(fcb, NULL, NULL))) break; wcs_sleep(lcnt); } assert(RMS$_NORMAL == status); if (RMS$_NORMAL == status) { status = sys$close(fcb); assert(RMS$_NORMAL == status); } if (RMS$_NORMAL != status) exit_stat = EXIT_WRN; } else exit_stat = EXIT_ERR; if (RMS$_NORMAL != status) gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0); if ((MAX_RMS_RECORDSIZE - SIZEOF(shmpool_blk_hdr)) < cs_data->blk_size) gtm_putmsg(VARLSTCNT(5) ERR_MUNOSTRMBKUP, 3, fcb->fab$b_fns, fcb->fab$l_fna, 32 * 1024 - DISK_BLOCK_SIZE); return exit_stat; }
unsigned char mu_cre_file(void) { char *cc = NULL, path[MAX_FBUFF + 1], errbuff[512]; unsigned char buff[DISK_BLOCK_SIZE]; int fd = -1, i, lower, upper, status, padded_len, padded_vbn, norm_vbn; uint4 raw_dev_size; /* size of a raw device, in bytes */ int4 blocks_for_create, blocks_for_extension, save_errno; GTM_BAVAIL_TYPE avail_blocks; file_control fc; mstr file; parse_blk pblk; unix_db_info udi_struct, *udi; char *fgets_res; gd_segment *seg; error_def(ERR_NOSPACECRE); error_def(ERR_LOWSPACECRE); assert((-(sizeof(uint4) * 2) & sizeof(sgmnt_data)) == sizeof(sgmnt_data)); cs_addrs = &udi_struct.s_addrs; cs_data = (sgmnt_data_ptr_t)NULL; /* for CLEANUP */ memset(&pblk, 0, sizeof(pblk)); pblk.fop = (F_SYNTAXO | F_PARNODE); pblk.buffer = path; pblk.buff_size = MAX_FBUFF; file.addr = (char*)gv_cur_region->dyn.addr->fname; file.len = gv_cur_region->dyn.addr->fname_len; strncpy(path,file.addr,file.len); *(path+file.len) = '\0'; if (is_raw_dev(path)) { /* do not use a default extension for raw device files */ pblk.def1_buf = DEF_NODBEXT; pblk.def1_size = sizeof(DEF_NODBEXT) - 1; } else { pblk.def1_buf = DEF_DBEXT; pblk.def1_size = sizeof(DEF_DBEXT) - 1; } if (1 != (parse_file(&file, &pblk) & 1)) { PRINTF("Error translating filename %s.\n", gv_cur_region->dyn.addr->fname); return EXIT_ERR; } path[pblk.b_esl] = 0; if (pblk.fnb & F_HAS_NODE) { /* Remote node specification given */ assert(pblk.b_node); PRINTF("Database file for region %s not created; cannot create across network.\n", path); return EXIT_WRN; } udi = &udi_struct; udi->raw = is_raw_dev(pblk.l_dir); if (udi->raw) { fd = OPEN(pblk.l_dir,O_EXCL | O_RDWR); if (-1 == fd) { SPRINTF_AND_PERROR("Error opening file %s\n"); return EXIT_ERR; } if (-1 != (status = (ssize_t)lseek(fd, 0, SEEK_SET))) { DOREADRC(fd, buff, sizeof(buff), status); } else status = errno; if (0 != status) { SPRINTF_AND_PERROR("Error reading header for file %s\n"); return EXIT_ERR; } if (!memcmp(buff, GDS_LABEL, STR_LIT_LEN(GDS_LABEL))) { char rsp[80]; PRINTF("Database already exists on device %s\n", path); PRINTF("Do you wish to re-initialize (all current data will be lost) [y/n] ? "); FGETS(rsp, 79, stdin, fgets_res); if ('y' != *rsp) return EXIT_NRM; } PRINTF("Determining size of raw device...\n"); for(i = 1; read(fd, buff, sizeof(buff)) == sizeof(buff);) { i *= 2; lseek(fd, (off_t)i * BUFSIZ, SEEK_SET); } lower = i / 2; upper = i; while ((lower + upper) / 2 != lower) { i = (lower + upper) / 2; lseek(fd, (off_t)i * BUFSIZ, SEEK_SET); if (read(fd, buff, sizeof(buff)) == sizeof(buff)) lower = i; else upper = i; } raw_dev_size = i * BUFSIZ; } else { fd = OPEN3(pblk.l_dir, O_CREAT | O_EXCL | O_RDWR, 0600); if (-1 == fd) { SPRINTF_AND_PERROR("Error opening file %s\n"); return EXIT_ERR; } if (0 != (save_errno = disk_block_available(fd, &avail_blocks, FALSE))) { errno = save_errno; SPRINTF_AND_PERROR("Error checking available disk space for %s\n"); CLEANUP(EXIT_ERR); return EXIT_ERR; } seg = gv_cur_region->dyn.addr; /* blocks_for_create is in the unit of DISK_BLOCK_SIZE */ blocks_for_create = DIVIDE_ROUND_UP(sizeof(sgmnt_data), DISK_BLOCK_SIZE) + 1 + (seg->blk_size / DISK_BLOCK_SIZE * ((DIVIDE_ROUND_UP(seg->allocation, BLKS_PER_LMAP - 1)) + seg->allocation)); if ((uint4)avail_blocks < blocks_for_create) { gtm_putmsg(VARLSTCNT(6) ERR_NOSPACECRE, 4, LEN_AND_STR(path), blocks_for_create, (uint4)avail_blocks); send_msg(VARLSTCNT(6) ERR_NOSPACECRE, 4, LEN_AND_STR(path), blocks_for_create, (uint4)avail_blocks); CLEANUP(EXIT_ERR); return EXIT_ERR; } blocks_for_extension = (seg->blk_size / DISK_BLOCK_SIZE * ((DIVIDE_ROUND_UP(EXTEND_WARNING_FACTOR * seg->ext_blk_count, BLKS_PER_LMAP - 1)) + EXTEND_WARNING_FACTOR * seg->ext_blk_count)); if ((uint4)(avail_blocks - blocks_for_create) < blocks_for_extension) { gtm_putmsg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, LEN_AND_STR(path), EXTEND_WARNING_FACTOR, blocks_for_extension, DISK_BLOCK_SIZE, (uint4)(avail_blocks - blocks_for_create)); send_msg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, LEN_AND_STR(path), EXTEND_WARNING_FACTOR, blocks_for_extension, DISK_BLOCK_SIZE, (uint4)(avail_blocks - blocks_for_create)); } } gv_cur_region->dyn.addr->file_cntl = &fc; fc.file_info = (void*)&udi_struct; udi->fd = fd; cs_data = (sgmnt_data_ptr_t)malloc(sizeof(sgmnt_data)); memset(cs_data, 0, sizeof(*cs_data)); cs_data->createinprogress = TRUE; cs_data->semid = INVALID_SEMID; cs_data->shmid = INVALID_SHMID; /* We want our datablocks to start on what would be a block boundary within the file so pad the fileheader if necessary to make this happen. */ padded_len = ROUND_UP(sizeof(sgmnt_data), BLK_SIZE); padded_vbn = DIVIDE_ROUND_UP(padded_len, DISK_BLOCK_SIZE) + 1; norm_vbn = DIVIDE_ROUND_UP(sizeof(sgmnt_data), DISK_BLOCK_SIZE) + 1; cs_data->start_vbn = padded_vbn; cs_data->free_space += (padded_vbn - norm_vbn) * DISK_BLOCK_SIZE; cs_data->acc_meth = gv_cur_region->dyn.addr->acc_meth; if (udi->raw) { /* calculate total blocks, reduce to make room for the * database header (size rounded up to a block), then * make into a multiple of BLKS_PER_LMAP to have a complete bitmap * for each set of blocks. */ cs_data->trans_hist.total_blks = raw_dev_size - ROUND_UP(sizeof(sgmnt_data), DISK_BLOCK_SIZE); cs_data->trans_hist.total_blks /= (uint4)(((gd_segment *)gv_cur_region->dyn.addr)->blk_size); if (0 == (cs_data->trans_hist.total_blks - DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, BLKS_PER_LMAP - 1) % (BLKS_PER_LMAP - 1))) cs_data->trans_hist.total_blks -= 1; /* don't create a bitmap with no data blocks */ cs_data->extension_size = 0; PRINTF("Raw device size is %dK, %d GDS blocks\n", raw_dev_size / 1000, cs_data->trans_hist.total_blks); } else { cs_data->trans_hist.total_blks = gv_cur_region->dyn.addr->allocation; /* There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks * and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this * manner as every non-bitmap block must have an associated bitmap) */ cs_data->trans_hist.total_blks += DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, BLKS_PER_LMAP - 1); cs_data->extension_size = gv_cur_region->dyn.addr->ext_blk_count; } mucregini(cs_data->trans_hist.total_blks); cs_data->createinprogress = FALSE; LSEEKWRITE(udi->fd, 0, cs_data, sizeof(sgmnt_data), status); if (0 != status) { SPRINTF_AND_PERROR("Error writing out header for file %s\n"); CLEANUP(EXIT_ERR); return EXIT_ERR; } cc = (char*)malloc(DISK_BLOCK_SIZE); memset(cc, 0, DISK_BLOCK_SIZE); LSEEKWRITE(udi->fd, (cs_data->start_vbn - 1) * DISK_BLOCK_SIZE + ((off_t)(cs_data->trans_hist.total_blks) * cs_data->blk_size), cc, DISK_BLOCK_SIZE, status); if (0 != status) { SPRINTF_AND_PERROR("Error writing out end of file %s\n"); CLEANUP(EXIT_ERR); return EXIT_ERR; } if ((!udi->raw) && (-1 == CHMOD(pblk.l_dir, 0666))) { SPRINTF_AND_PERROR("Error changing file mode on file %s\n"); CLEANUP(EXIT_WRN); return EXIT_WRN; } CLEANUP(EXIT_NRM); PRINTF("Created file %s\n", path); return EXIT_NRM; }