#include <Qp0lstdi.h> int Qp0lProcessSubtree ( Qlg_Path_Name_T *Path_Name, uint Subtree_level, Qp0l_Objtypes_List_t *Objtypes_array_ptr, uint Local_remote_obj, Qp0l_IN_EXclusion_List_t *IN_EXclusion_ptr, uint Err_recovery_action, Qp0l_User_Function_t *UserFunction_ptr, void *Function_CtlBlk_ptr, ...);
The Qp0lProcessSubtree() function searches the directory tree under a specific path name. It selects and passes objects, one at a time, to an exit program that is identified on its call. The exit program can be either a procedure or a program.
Qp0lProcessSubtree() performs recursive read operations to access any object in any file system. The order in which objects are selected and passed to the exit program can vary within a given file system and within a given directory, dependent on file system rules. The only guaranteed ordering is that all selected objects within a given directory are passed to the exit program before the parent directory is passed to the exit program.
The structure for this parameter follows.
Offset | Type | Field | |
---|---|---|---|
Dec | Hex | ||
0 | 0 | BINARY(4) | Number of object types |
4 | 4 | ARRAY(*) of CHAR(11) | Array of object types structure |
Qp0lProcessSubtree() verifies that valid object types are entered and returns the errno EINVAL when an object type that is not valid is entered. Although some object types are scoped to a specific file system, Qp0lProcessSubtree() does not validate object types according to file systems.
Valid special values for this parameter follow:
*ALLDIR: | Select all directory object types. This includes *LIB, *DIR, *FLR, *FILE, and *DDIR object types. |
*ALLQSYS: | Select all QSYS.LIB object types. This includes
all objects in the QSYS.LIB file system and all independent ASP QSYS.LIB file
systems which are available when the API is first called.
Note: IN_EXclusion_ptr must also be specified as an inclusion array. If *NOQSYS is specified, *ALLQSYS cannot also be specified. |
*ALLSTMF: | Select all stream file object types. This includes *MBR, *DOC, *STMF, *DSTMF, and *USRSPC object types. |
*MBR: | Select all database file member types. |
*NOQSYS: | Exclude all QSYS.LIB object types. This includes
all objects in the QSYS.LIB file system and all independent ASP QSYS.LIB file
systems which are available when the API is first called.
Note: This special value only has meaning if '/' or '/asp_name' is specified for the Path_Name parameter (where asp_name is the name of an independent ASP which is available when the API is first called). Additionally, if IN_EXclusion_ptr is specified, it must only be as an exclusion array. If *ALLQSYS is specified, *NOQSYS cannot also be specified. |
0 | QP0L_LOCAL_REMOTE_OBJ: Both local and remote objects are passed to the exit program. |
1 | QP0L_LOCAL_OBJ: Only local objects are passed to the exit program. |
2 | QP0L_REMOTE_OBJ: Only remote objects are passed to the exit program. |
Use an inclusive list to specify multiple path names for searches on a single call to Qp0lProcessSubtree() versus using the Path_Name parameter, which searches only one path per call. The Path_Name parameter and an inclusive list are mutually exclusive. EINVAL is returned if both parameters are specified. The IN_EXclusion_ptr must be NULL if not used. All of the rules that apply to a single Path_Name entry apply to each inclusive list entry.
While an inclusion list allows the caller of Qp0lProcessSubtree() to identify multiple path names for processing, Qp0lProcessSubtree() does not perform any verification to ensure uniqueness of path names or to verify any other relationship between path names entered in the inclusion array. For example, if the path names entered represent nested directories, Qp0lProcessSubtree() calls the exit program multiple times without any error message or other notification of this nesting.
Specify the root directory for a given file system as an exclusive list entry to eliminate that file system from a search.
All relative path names are relative to the current directory of the job that calls Qp0lProcessSubtree().
The structure for this parameter follows.
This points to a list of path names to either include or exclude from a search.
Offset | Type | Field | |
---|---|---|---|
Dec | Hex | ||
0 | 0 | BINARY(4) | IN_EXclusion pointer type |
4 | 4 | BINARY(4) | Number of pointers |
8 | 8 | CHAR(8) | Reserved |
16 | 10 | ARRAY(*) | Path name pointers |
0 | QP0L_INCLUSION_TYPE: An inclusion array is identified. |
1 | QP0L_EXCLUSION_TYPE: An exclusion array is identified. |
0 | QP0L_PASS_WITH_ERRORID: Calls the exit program and specifies the name (when the name is available) of the object being accessed when an error occurs. This value also sends a valid errno to the exit program. |
1 | QP0L_BYPASS_NO_ERRORID: Bypasses the object being accessed when an error occurs, and moves to process the next object in the tree without notification to the calling program or to the exit program that an error has occurred. |
2 | QP0L_JOBLOG_NO_ERRORID: Sends message CPDA1C0 to the job log to identify the object being accessed when an error occurs. This value returns to process the next object without notification to the calling program or to the exit program that an error has occurred. |
3 | QP0L_NULLNAME_ERRORID: Calls the exit program with a NULL object name and a valid errno. |
4 | QP0L_END_PROCESS_SUBTREE: Quits Qp0lProcessSubtree() when an error occurs, and returns to the calling program, regardless of the error type. Note that the exit program is still given a call but cannot override the caller's decision to end processing. Calling the exit program allows the exit program to perform other tasks before the API returns to the caller. For example, the exit program can put information in the function control block that can be processed by the caller when the caller regains control. |
The structure for this parameter follows.
This points to the user exit program. The exit program can be a procedure or a program.
Offset | Type | Field | |
---|---|---|---|
Dec | Hex | ||
0 | 0 | BINARY(4) | Function type flag |
4 | 4 | CHAR(10) | Program library |
14 | E | CHAR(10) | Program name |
24 | 18 | CHAR(1) | Multithreaded job action |
25 | 19 | CHAR(7) | Reserved |
32 | 20 | PP(*) | Procedure pointer to the exit procedure |
0 | QP0L_USER_FUNCTION_PTR: A user procedure is called. |
1 | QP0L_USER_FUNCTION_PGM: A user program is called. |
x'00' | QP0L_MLTTHDACN_SYSVAL: The API evaluates the
QMLTTHDACN system value to determine the action to take in a multithreaded job.
Although the API can make repetitive calls to an exit program, the system value
is evaluated once before Qp0lProcessSubtree() issues its first exit program
call. This value is used on subsequent calls until the API returns control to
its caller. Valid QMLTTHDACN system values follow:
|
||||||
x'01' | QP0L_MLTTHDACN_NOMSG: Call the exit program. Do not send an informational message. | ||||||
x'02' | QP0L_MLTTHDACN_MSG: Call the exit program. Send informational message CPI3C80. Qp0lProcessSubtree() may call the exit program multiple times; however, this message is sent only once for each call to Qp0lProcessSubtree(). | ||||||
x'03' | QP0L_MLTTHDACN_NO: The exit program is not called when the API determines that it is running in a multithreaded job. ENOTSAFE is returned. |
Note: Adopted authority is not used.
Authorization Required for Qp0lProcessSubtree()
Object Referred to | Authority Required | errno |
---|---|---|
Each directory, preceding the last component, in a Path Name | *X | EACCES |
The Path Name directory and all subdirectories of the Path Name that are included in the search. | *RX (See Note) | EACCES |
Each directory, preceding the last component, in any path name pointed to by the IN_EXclusion ptr | *X | EACCES |
The Path Name directory and all subdirectories of any path name pointed to by an inclusive list | *RX (See Note) | EACCES |
The object identified by the path name that is passed to the exit program, if the object is a user profile (*USRPRF) | Any authority greater than *EXCLUDE | EACCES |
Any called program pointed to by the UserFunction_ptr parameter | *X | EACCES |
Any library that contains the called program pointed to by the UserFunction_ptr parameter | *X | EACCES |
Note: If the directory or subdirectories have no objects in them, only *R is required. |
0 | Qp0lProcessSubtree() was successful. |
-1 | Qp0lProcessSubtree() was not successful. The errno variable is set to indicate the error. |
If Qp0lProcessSubtree() is not successful, the errno indicates one of the following errors:
Error condition | Additional information |
---|---|
[EACCES] |
If you are accessing a remote file through the Network File System, update operations to file permissions at the server are not reflected at the client until updates to data that is stored locally by the Network File System take place. (Several options on the Add Mounted File System (ADDMFS) command determine the time between refresh operations of local data.) Access to a remote file may also fail due to different mappings of user IDs (UID) or group IDs (GID) on the local and remote systems. |
[EAGAIN] | |
[EBADNAME] | |
[EBUSY] | |
[EDAMAGE] | |
[EFAULT] | |
[EINVAL] | |
[EIO] | |
[EISDIR] | |
[ELOOP] | |
[EMFILE] | |
[ENAMETOOLONG] | |
[ENFILE] | |
[ENOENT] | |
[ENOMEM] | |
[ENOSPC] | |
[ENOSYSRSC] | |
[ENOTAVAIL] | |
[ENOTDIR] | |
[ENOTSAFE] | |
[EUNKNOWN] |
The following message may be sent from this function:
Message ID | Error Message Text |
---|---|
CPE3418 E | Possible APAR condition or hardware failure. |
CPF3CF2 E | Error(s) occurred during running of &1 API. |
CPFA0D4 E | File system error occurred. Error number &1. |
CPF9872 E | Program or service program &1 in library &2 ended. Reason code &3. |
Qp0lProcessSubtree() does not perform any object locking, other than what is done when opening a directory to read the objects it contains, so that the exit program does not encounter or need to manage locks held by Qp0lProcessSubtree().
If Qp0lProcessSubtree() encounters a directory that is locked, Qp0lProcessSubtree() uses the defined Err_recovery_action to determine how to handle the locked condition. Locks on objects that are not directories have no effect on Qp0lProcessSubtree().
Once Qp0lProcessSubtree() has started searching a path, its search results may be affected by operations that update the organization of objects within the specifed directory tree. This includes but is not limited to the following:
When the last component of the path name supplied on the initial call of Qp0lProcessSubtree() is a symbolic link, Qp0lProcessSubtree() resolves and follows the initial link to its target and performs its normal functions on the target. All other symbolic links that are encountered in the same search are not resolved to their targets.
If the path name supplied on the initial call of Qp0lProcessSubtree() is a symbolic link that points to another file system or that points to a remote file system, the API resolves and processes the initial link only. It does not resolve other symbolic links that are encountered in the same search. However, if the caller specified that remote objects are not processed, but the initial path name (whether a symbolic link or not) points to a remote file system, the link is not resolved. Qp0lProcessSubtree() calls the exit program with a NULL path name and an indicator that Qp0lProcessSubtree() has completed successfully without any error indicators to the exit program.
When *SYMLNK is specified as part of the selection criteria, Qp0lProcessSubtree() does not resolve the selected names.
There are three separate parameters that control error recovery during a search. The caller of the API determines how an error should be reported to the exit program by setting the Err_recovery_actions parameter. The API sets the Selection status pointer and sends it to the exit program to indicate one of four conditions: the API search status is OK, the last object has been processed, the API has encountered recoverable errors, or the search cannot continue. For error conditions it also sends a valid errno. The exit program returns an indicator back to the API either to continue or to end the search by setting the Return value pointer. For error conditions, it also returns a valid errno, pointed to by the Return value pointer. Each time Qp0lProcessSubtree() regains control from the exit program, it determines whether the search should continue or end by evaluating the Err_recovery_actions parameter, its Selection status pointer, and the Return value pointer. Upon ending, Qp0lProcessSubtree() returns 0 to indicate a successful search, or a -1 and an errno to indicate the error condition. This errno may have been set by the exit program (Return value pointer).
This error recovery design allows for flexibility in handling errors between the caller, the API, and the exit program. Whenever an unrecoverable error occurs, if possible, the exit program is given a final call; this call allows the exit program to do such tasks as cleanup or to put information in the function control block, or to record information about the error. However, the exit program cannot decide that the search should continue. The API will return to its caller when it regains control. There are only two specific instances in which the API determines that the exit program is not called:
Following is a diagram showing the flow and relationship of these parameters.
Following are scenarios showing calls and the results of calls to Qp0lProcessSubtree(). Directory Structure A and Directory Structure B define the input directory structure for these scenarios.
This directory structure represents three subdirectories (a, b, c), three objects (x, y, z), and a symbolic link (t).
This directory structure represents six subdirectories (a, b, c, d, e, f) and seven objects (t, u, v, w, x, y, z).
This scenario assumes processing a directory as shown by Directory Structure A in Figure above.
This scenario shows a call to the API without any criteria to filter the
selection of objects in the path being searched. If the API call were coded
with the parameter values as shown by Input value in Scenario 1 API Input, the exit program would be called nine
times and would pass the object names as shown by the Object Name
Pointer in Results of a call. Because
QP0L_SUBTREE_YES is specified, all of the directories in the path will be
opened and the name of all the objects that they contain will be passed to the
exit program. Note that the only guaranteed order is that parent directories
are passed to the exit program after all of their children.
Input Parameter | Input value |
---|---|
*Path_Name | '/' ('/' processes every directory on the system and is not recommended if performance is a consideration) |
Subtree_level | QP0L_SUBTREE_YES |
*Objtypes_array_ptr | NULL |
Local_remote_obj | QP0L_LOCAL_REMOTE_OBJ |
*IN_EXclusion_ptr | NULL |
Err_recovery_action | QP0L_PASS_WITH_ERRORID |
*UserFunction_ptr | QP0L_USER_FUNCTION_PTR |
*Function_CtlBlk_ptr | NULL |
Exit Program Call Count | Object Name Pointer |
---|---|
1 | /a/b/y |
2 | /a/b |
3 | /a/x |
4 | /a/t |
5 | /a/c/z |
6 | /a/c |
7 | /a |
8 | / |
9 | NULL path name (indicates the API completed) |
This scenario assumes processing a directory as shown by Directory Structure A in the Figure above.
This shows a call to the API with the Subtree level parameter set to retrieve only one level, without any object filtering. Since QP0L_SUBTREE_NO is specified, the names of all objects in the path will be passed to the exit program, however, none of the directories will be opened. This allows a caller to perform tasks such as identifying all of the root objects for a file system. For example, this would identify all of the first level folders, when processing against the QDLS file system. Then the API can be called recursively from within the exit program, with each of these folders specified as the path to be searched.
If the API call were coded with the parameter values as shown by Input
value in Scenario 2 API Input, the exit program
would be called six times and would pass the object names as shown by the
Object Name Pointer in Results of a call.
Input Parameter | Input value |
---|---|
*Path_Name | '/a' |
Subtree_level | QP0L_SUBTREE_NO |
*Objtypes_array_ptr | NULL |
Local_remote_obj | QP0L_LOCAL_REMOTE_OBJ |
*IN_EXclusion_ptr | NULL |
Err_recovery_action | QP0L_PASS_WITH_ERRORID |
*UserFunction_ptr | QP0L_USER_FUNCTION_PTR |
*Function_CtlBlk_ptr | NULL |
Exit Program Call Count | Object Name Pointer |
---|---|
1 | /a/b |
2 | /a/x |
3 | /a/t |
4 | /a/c |
5 | /a |
6 | NULL path name (indicates the API completed) |
This scenario assumes processing a directory as shown by Directory Structure B in the Figure above.
This scenario represents a call to the API with an inclusion list. Note that the Path Name parameter is not used as the starting directory since each entry in an inclusion list is treated as a starting directory.
If the API call were coded with the parameter values as shown by Input value in Scenario 3 API Input, the exit program would be called six times and would pass the object names as shown by the Object Name Pointer in Results of a call.
Note that /a/b/c/d/v could be returned before /a/b/c/d/u, as shown in this scenario, since children in a directory can be returned in any order. The only guaranteed order is that the exit program is called with all children objects before being called with the parent to allow the exit program to delete directories if desired.
Input Parameter | Input value |
---|---|
*Path_Name | NULL (not used with an inclusion list) |
Subtree_level | QP0L_SUBTREE_YES |
*Objtypes_array_ptr | '*DIR ' '*STMF ' |
Local_remote_obj | QP0L_LOCAL_OBJ |
*IN_EXclusion_ptr | QP0L_INCLUSION_TYPE, '/a/b/c/d/' '/a/b/c/e/' |
Err_recovery_action | QP0L_PASS_WITH_ERRORID |
*UserFunction_ptr | QP0L_USER_FUNCTION_PTR |
*Function_CtlBlk_ptr | NULL |
Exit Program Call Count | Object Name Pointer |
---|---|
1 | /a/b/c/d/v |
2 | /a/b/c/d/u |
3 | /a/b/c/d |
4 | /a/b/c/e/w |
5 | /a/b/c/e/ |
6 | NULL path name (indicates the API completed) |
This scenario assumes processing a directory as shown by Directory Structure B in the Figure above.
This scenario represents a call to the API with an exclusion list. Note that each relative entry in the exclusion list is resolved relative to the current working directory at the time the API is called. This scenario assumes that the current working directory is /a/b/.
If the API call were coded with the parameter values as shown by Input value in Scenario 4 API Input, the exit program would be called eight times and would pass the object names as shown by the Object Name Pointer in Results of a call.
This scenario also shows that children in a directory can be returned in any order. The only guaranteed order is that the exit program is called with all children objects before being called with the parent to allow the exit program to delete directories if desired.
Input Parameter | Input value |
---|---|
*Path_Name | '/a/b/' |
Subtree_level | QP0L_SUBTREE_YES |
*Objtypes_array_ptr | '*DIR ' '*STMF ' |
Local_remote_obj | QP0L_LOCAL_OBJ |
*IN_EXclusion_ptr | QP0L_EXCLUSION_TYPE, 'c/d/' 'c/e/' |
Err_recovery_action | QP0L_PASS_WITH_ERRORID |
*UserFunction_ptr | QP0L_USER_FUNCTION_PTR |
*Function_CtlBlk_ptr | NULL |
Exit Program Call Count | Object Name Pointer |
---|---|
1 | /a/b/t |
2 | /a/b/c/y |
3 | /a/b/c/f/z |
4 | /a/b/c/f |
5 | /a/b/c/x |
6 | /a/b/c |
7 | /a/b |
8 | NULL path name (indicates the API completed) |
See Code disclaimer information for information pertaining to code examples.
Following is a code example showing a call to the Qp0lProcessSubtree() API with a procedure as the exit program:
/*****************************************************************/ /*****************************************************************/ #include <Qp0lstdi.h> #include <stdio.h> #include <errno.h> #include <qtqiconv.h> void Obj_Print_Function (uint *Selection_status_pointer, uint *Error_value_pointer, uint *Return_value_pointer, Qlg_Path_Name_T *Object_name_pointer, void *Function_control_block_pointer) { /****************************************************************/ /* This exit program example prints the names, one at a time, */ /* of each entry in a directory structure that it receives on */ /* each call from Qp0lProcessSubtree(). */ /****************************************************************/ #define PATH_TYPE_POINTER 0x00000001 /* If this flag is on, */ /* the qlg structure contains a */ /* pointer to the path name. */ /* Otherwise, the path name is in */ /* contiguous storage within the */ /* qlg structure. */ typedef union pn_input_type { char pn_char_type[256]; /* path name is in */ /* contiguous storage */ char *pn_ptr_type; /* path name is a pointer */ }; typedef struct pnstruct { Qlg_Path_Name_T qlg_struct; union pn_input_type pn; }; struct pnstruct *pns; char *path_ptr; size_t insz; size_t outsz = 1000; char outbuf[1000]; char *outbuf_ptr; iconv_t cd; size_t ret_iconv; QtqCode_T toCode = {37,0,0,0,0,0}; QtqCode_T fromCode = {61952,0,0,1,0,0}; if (*Selection_status_pointer == QP0L_SELECT_OK) { if (Object_name_pointer != NULL) { /************************************************************/ /* Point to the pathname and get the size of the pathname */ /* that was sent from the Qp0lProcessSubtree() API. The */ /* format of the pathname must be determined by evaluating */ /* Path_Type in the qlg structure. */ /************************************************************/ pns = (struct pnstruct *)Object_name_pointer; if (Object_name_pointer->Path_Type & PATH_TYPE_POINTER) { path_ptr = pns->pn.pn_ptr_type; } else { path_ptr = (char *)(pns->pn.pn_char_type); } insz = pns->qlg_struct.Path_Length; /************************************************************/ /* Initialize the print buffer. */ /************************************************************/ outbuf_ptr = (char *)outbuf; memset(outbuf_ptr, 0x00, insz); /************************************************************/ /* Use iconv to convert from 61952 to the job CCSID. */ /* REMEMBER iconv will change the data that it receives. */ /************************************************************/ cd = /* Open the conversion descriptor.*/ QtqIconvOpen(&toCode, &fromCode); if (cd.return_value == -1) { /*********************************************************/ /* If conversion descriptor was not opened successfully, */ /* return an error and errno (ECONVERT) to the API. */ /*********************************************************/ *Return_value_pointer = errno; return; } ret_iconv = /* Perform the conversion.*/ (iconv(cd, (char **)&(path_ptr), &insz, (char **)&(outbuf_ptr), &outsz)); if (ret_iconv != 0) { /*********************************************************/ /* If the conversion failed, close the conversion */ /* descriptor and return an error and errno (ECONVERT) */ /* to the API. */ /*********************************************************/ ret_iconv= iconv_close(cd); *Return_value_pointer = errno; return; } /************************************************************/ /* Print the name of the object being processed and close */ /* the conversion descriptor. */ /************************************************************/ printf("In User Exit Program. Path is %s.\n", outbuf); ret_iconv = iconv_close(cd); } /* end Object_name_pointer != NULL */ else { printf("In User Exit Program with a null Pathname \n"); } } /* end *Selection_status_pointer == QP0L_SELECT_OK */ *Return_value_pointer = 0; } /* end Exit program */ int main (int argc, char *argv[]) { #define MYPN "/TestDir" const int zero = 0; const char US_const[3]= "US"; const char Language_const[4]="ENU"; const char Path_Name_Del_const[2]= "/"; const char LibObj_const[12]= "*LIB "; typedef struct pnstruct { Qlg_Path_Name_T qlg_struct; char pn[50]; /* Must be greater than */ /* or equal the length */ /* of the path name. */ }; struct pnstruct pns; Qp0l_Objtypes_List_t MyObj_types; Qp0l_User_Function_t User_function; struct { uint AnyData_to_the_exitprogram; uint AnyData_not_processed_by_the_API; } CtlBlkAreaName; int rc; /***************************************************************/ /* In this example, the pathname is defined by MYPN as TestDir */ /* and it is assumed that the TestDir directory exists on the */ /* system. Various other functions or other routines could be */ /* included here to (for example): */ /* 1) determine the beginning search directory. */ /* 2) construct the path name in the correct format. */ /* 3) others... */ /***************************************************************/ /***************************************************************/ /***************************************************************/ /* Initialize Qp0lProcessSubtree() API Parameters */ /***************************************************************/ memset((void*)&pns, 0x00, sizeof(struct pnstruct)); pns.qlg_struct.CCSID = 37; memcpy(pns.qlg_struct.Country_ID,US_const,2); memcpy(pns.qlg_struct.Language_ID,Language_const,3); pns.qlg_struct.Path_Type = zero; pns.qlg_struct.Path_Length = sizeof(MYPN)-1; memcpy(pns.qlg_struct.Path_Name_Delimiter,Path_Name_Del_const,1); memcpy(pns.pn,MYPN,sizeof(MYPN)); MyObj_types.Number_Of_Objtypes = zero; memset((void *)&User_function, 0x00, sizeof(Qp0l_User_Function_t)); User_function.Function_Type = QP0L_USER_FUNCTION_PTR; User_function.Mltthdacn[0] = QP0L_MLTTHDACN_NOMSG; User_function.Procedure = &Obj_Print_Function; if (rc = Qp0lProcessSubtree((Qlg_Path_Name_T *)&pns, QP0L_SUBTREE_YES, (Qp0l_Objtypes_List_t *)NULL, QP0L_LOCAL_REMOTE_OBJ, (Qp0l_IN_EXclusion_List_t *)NULL, QP0L_PASS_WITH_ERRORID, &User_function, &CtlBlkAreaName) == 0) { printf("Qp0lProcessSubtree() Successful : error = %d\n", errno); } else {/*unsuccessful return from Qp0lProcessSubtree() API */ printf("ERROR on Qp0lProcessSubtree(): error = %d\n", errno); perror("Error message"); } } /* end main */
Top | UNIX-Type APIs | APIs by category |