Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Qsam data set #109

Open
wants to merge 2 commits into
base: v1.x/staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 233 additions & 1 deletion c/datasetjson.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
#include "vsam.h"
#include "qsam.h"

typedef int EXTF();
#pragma linkage(EXTF,OS_UPSTACK)

#define INDEXED_DSCB 96

static char defaultDatasetTypesAllowed[3] = {'A','D','X'};
Expand Down Expand Up @@ -2251,9 +2254,238 @@ void respondWithHLQNames(HttpResponse *response, MetadataQueryCache *metadataQue
#endif /* __ZOWE_OS_ZOS */
}

/*************************/
#define FIELD_MAX_LENGTH 1024
#define REQUEST_MAX_LENGTH 2048

#endif /* not METTLE - the whole module */
int qsamAllocFile( qsamFileRequest *request, char* message,
daveyc marked this conversation as resolved.
Show resolved Hide resolved
int messageLength){
#ifdef __ZOWE_OS_ZOS
char *baseRequest = "alloc new catalog msg(2) ";
char *freeRequest = "free ";
char tempString[20] = {0};

char field[FIELD_MAX_LENGTH];
int status, value;
char *ptr;

/* Must supply daName */
if (request->daName == NULL) {
return -1;
}

/* Allocate structure in A31 space */
EXTF *bpxwdyn=(EXTF *)fetch("BPXWDYN");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no matching release() for this fetch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing that I have read has mentioned anything about releasing an item that has been fetched. What is your source for this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source is in the manual. It won't leak resources because the CDE has a use count but it's always good to clean up. You could stash the bpxwdyn pointer in a static variable and fetch it once. It will get released when the task ends.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info. None of the examples on bpxwdyn has the release function shown.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, I'm not sure that it won't leak memory because there is a fetch control block associated with fetch used by LE. The underlying LOAD macro used by fetch is fine but I would still always call DELETE when I use a LOAD.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a fetch issue not related to BPXWDYN. fetch is is just a callable service.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I would assume that any example showing how to use bpxwdyn would also show the release of the function since it already show the fetch of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed

ifakhrutdinov marked this conversation as resolved.
Show resolved Hide resolved
ALLOC_STRUCT31(
STRUCT31_NAME(below2G),
STRUCT31_FIELDS(
char request[REQUEST_MAX_LENGTH];
)
);

/* setup initial request string */
strncpy( below2G->request, baseRequest, sizeof(below2G->request));
sbollingerAtRocket marked this conversation as resolved.
Show resolved Hide resolved

/* Initialize the DD/FI field */
ptr = (request->ddName == NULL ? QSAM_DEFAULT_DDNAME: request->ddName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have code for dynalloc in https://github.com/zowe/zowe-common-c/blob/master/c/dynalloc.c, you should re-use/enhance code from there.

snprintf(field, sizeof(field)-1, "FI(%s) ", ptr);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize daName */
snprintf(field, sizeof(field)-1, "DA(%s) ", request->daName);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize data set type */
if ((ptr = request->dsnType) != NULL) {
snprintf(field, sizeof(field)-1, "DSNTYPE(%s) ", ptr);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize organization */
ptr = (request->organization == NULL ?
QSAM_DEFAULT_ORGANIZATION: request->organization);
snprintf(field, sizeof(field)-1, "DSORG(%s) ", ptr);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize record format */
ptr = (request->recordFormat == NULL ?
QSAM_DEFAULT_RECORDFORMAT: request->recordFormat);
snprintf(field, sizeof(field)-1, "RECFM(%s) ", ptr);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize record length */
value = (request->recordLength == 0 ?
QSAM_DEFAULT_RECORDLENGTH: request->recordLength);
snprintf(field, sizeof(field)-1, "LRECL(%d) ", value);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize block size*/
value = (request->blkSize == 0 ?
QSAM_DEFAULT_BLKSIZE: request->blkSize);
snprintf(field, sizeof(field)-1, "BLKSIZE(%d) ", value);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize storage type */
if (request->storageClass != NULL) {
snprintf(field, sizeof(field)-1, "STORCLAS(%s) ", request->storageClass);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize file data type */
if (request->fileData != NULL) {
snprintf(field, sizeof(field)-1, "FILEDATA(%s) ", request->fileData);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize file data type */
if (request->eattr != NULL) {
strncpy (tempString, request->eattr, sizeof (tempString) -1);
strupcase(tempString);
if (strncmp( tempString, "TRUE", 5)) {
snprintf(field, sizeof(field)-1, "EATTR(OPT) ");
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}
}

/* Initialize number of generations */
if (request->numGenerations != 0) {
snprintf(field, sizeof(field)-1, "MAXGENS(%d) ", request->numGenerations);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize volumn if defined */
if (request->volume != NULL) {
snprintf(field, sizeof(field)-1, "VOL(%s) ", request->volume);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize dataClass if defined */
if (request->dataClass != NULL) {
snprintf(field, sizeof(field)-1, "DATACLAS(%s) ", request->dataClass);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize management class if defined */
if (request->manageClass != NULL) {
snprintf(field, sizeof(field)-1, "MGMTCLAS(%s) ", request->manageClass);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize management class if defined */
if (request->averageRecord != NULL) {
//snprintf(field, sizeof(field)-1, "BLOCK(%s) ", request->averageRecord);
snprintf(field, sizeof(field)-1, "AVGREC(%s) ", request->averageRecord);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize expiration data */
if (request->expiration != NULL) {
snprintf(field, sizeof(field)-1, "EXPDL(%s) ", request->expiration);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/* Initialize expiration data */
if (request->spaceUnit != NULL) {
snprintf(field, sizeof(field)-1, "SPACE(%s) ", request->spaceUnit);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
}

/****************************/
/* Create the qsam data set */
/****************************/
printf (" REQUEST: %s\n", below2G->request);
ifakhrutdinov marked this conversation as resolved.
Show resolved Hide resolved
status = bpxwdyn(below2G->request);

/* If error, don't try to free, decipher error code */
if (status != 0) {
int cause = 0, reasonIndex;
char *reason;

/* status between -20 and -9999 represents Key errors. */
/* The key index is (-status -20) */
/* status below -10000 has the IEFDB476 return code in */
/* lower 2 digits (decimal) of the status. */
/* Status code between -1610612737 and -2147483648 */
/* contains the S99ERROR code. */
reason = strtok(below2G->request, " ");
sprintf(field,"", "");
if ((status <= -20) && (status >= -9999)) {
cause = (-status - 20) %100;
ifakhrutdinov marked this conversation as resolved.
Show resolved Hide resolved
for (int i=0; i < cause -1; i ++) {
reason = strtok(NULL, " ");
// printf("G1: reason: %s\n", reason);
if (reason == NULL) {
break;
}
}
if (reason != NULL) {
int reasondIndex = -status / 100;
snprintf(field, sizeof(field)-1, " Field %s Error: Code %d",
reason, reasondIndex);
}
}
if ((-32*1024 <= status) && (status < -10000)) {
cause = (-status - 20) %100;
snprintf(field, sizeof(field)-1, "IEFDB476 Error Code %d", cause);
}
if ((status <= -1610612737) && (status >= -2147483648)) {
snprintf(field, sizeof(field)-1, "S99INFO Error Code %08x", status);
}

/* Write error message if one found */
if ((message != NULL) && strlen(field)) {
strncpy( message, field, messageLength);
}
zowelog(NULL, LOG_COMP_RESTDATASET, ZOWE_LOG_SEVERE,
"Create File %s Failed:: %s\n", request->daName, message);
goto freeStruct;
}

/* If created the file, then free/close it up */
zowelog(NULL, LOG_COMP_RESTDATASET, ZOWE_LOG_INFO,
"Create File:: Request: %s\n",below2G->request);

strncpy( below2G->request, freeRequest, sizeof(below2G->request));

/* Initialize the DD/FI field */
ptr = (request->ddName == NULL ? QSAM_DEFAULT_DDNAME: request->ddName);
snprintf(field, sizeof(field)-1, "fi(%s) ", ptr);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));

/* Initialize daName */
snprintf(field, sizeof(field)-1, "da(%s) ", request->daName);
strncat( below2G->request, field,
sizeof (below2G->request) - strlen(below2G->request));
status = bpxwdyn(below2G->request);

/* free the structure */
freeStruct:
FREE_STRUCT31(
STRUCT31_NAME(below2G)
);
sbollingerAtRocket marked this conversation as resolved.
Show resolved Hide resolved
return status;
#endif /* __ZOWE_OS_ZOS */
}

#endif /* not METTLE - the whole module */

/*
This program and the accompanying materials are
Expand Down
2 changes: 2 additions & 0 deletions h/datasetjson.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "json.h"
#include "xml.h"
#include "jcsi.h"
#include "qsam.h"

#define DATA_STREAM_BUFFER_SIZE 4096

Expand Down Expand Up @@ -62,6 +63,7 @@ void respondWithDataset(HttpResponse* response, char* absolutePath, int jsonMode
void respondWithVSAMDataset(HttpResponse* response, char* absolutePath, hashtable *acbTable, int jsonMode);
void respondWithDatasetMetadata(HttpResponse *response);
void respondWithHLQNames(HttpResponse *response, MetadataQueryCache *metadataQueryCache);
int qsamAllocFile( qsamFileRequest *request, char* message, int messageLength);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no QSAM files or datasets, QSAM is an access method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From earlier comment. I am open to any name change from qsam. Following names in the jira ticket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ifakhrutdinov is correct. I would name it allocDataSet which covers both PS and PDS(E) data sets.

void updateDataset(HttpResponse* response, char* absolutePath, int jsonMode);
void updateVSAMDataset(HttpResponse* response, char* absolutePath, hashtable *acbTable, int jsonMode);
void deleteVSAMDataset(HttpResponse* response, char* absolutePath);
Expand Down
40 changes: 39 additions & 1 deletion h/qsam.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,45 @@ int bpamFind(char * __ptr32 dcb, char * __ptr32 memberName, int *reasonCode);
int bpamRead(void * __ptr32 dcb, void * __ptr32 buffer);
int bpamRead2(void * __ptr32 dcb, void * __ptr32 buffer, int *lengthRead);

#endif
/*
The following definitions are used to create a qsam file using BPXWDYN.
*/
#define QSAM_DEFAULT_DDNAME "DUMMY"
#define QSAM_DEFAULT_ORGANIZATION "PS"
#define QSAM_DEFAULT_RECORDFORMAT "F,B"
#define QSAM_DEFAULT_RECORDLENGTH 80
#define QSAM_DEFAULT_BLKSIZE 32720
#define QSAM_DEFAULT_EXTENT 1
#define QSAM_DEFAULT_FILEDATA "TEXT"
#define QSAM_DEFAULT_VOLUME

typedef struct qsamFileRequest_tag {
char *ddName;
char *daName; /* Name of file */
char *manageClass;
char *storageClass;
char *fileData; /* Data type: TEXT or BINARY ??? */
char *volume;
char *dsnType; /* LIBRARY,LIBRAY1,PDS,HFS,EXTREQ,EXTPREF,BASIC,LARGE*/
char *eattr; /* extended attribute: true/false */

char *organization; /* PS, PO, DA */
char *recordFormat; /* F - fixed, */
int recordLength;
int blkSize;
int primary;
int secondary;
int fileSize; /* Size of file*/
int numGenerations;
int avrBlockLength;
char *dataClass;
char *averageRecord; /* M, K or U */
char *expiration;
char *spaceUnit; /* BLKS, TRKS, CYCLS, KB, MB, BYTES */
int dirBlk;
} qsamFileRequest;
ifakhrutdinov marked this conversation as resolved.
Show resolved Hide resolved

#endif /* End __QSAM__ */


/*
Expand Down