On 07-Apr-2015 16:12 -0500, Glenn Gundermann wrote:

Does the access API work for a folder or does it have to be a file?

A directory, folder, or file; irrespective of nomenclature, all can be target of an /access/ request; any of access, accessx, QlgAccess, QlgAccessx APIs to "Determine file accessibility". Presumably the /folder/ reference is not to the *FLR object in the /QDLS file system, but even that should be capable of being /accessed/ under that path. According to the following doc reference, the /access/ of a *DIR object [sometimes referred to as a /folder/ rather than directory] will be audited [as a read/search operation], so the logical inference for support is conspicuous:
<http://www.ibm.com/support/knowledgecenter/api/content/ssw_ibm_i_72/rzarl/rzarle21.htm>
_Operations for Directory_ (*DIR)


I was hoping it works for a folder but the information in the IBM
Knowledge Center says a file.

Per the IFS being representative of the world-view in which essentially everything is referred to as a /file/, that nomenclature and lack of distinction is not surprising, and almost expected. Easy enough for anyone to submit a reader-comment, if so inclined, to ask that [and how] the docs might better explain what is supported.

Despite the use of the term /file/ so generically, at least a hint of support exists for explicitly naming a directory [e.g. last character is a slash] as the first argument can be inferred from the list of possible Error Conditions having included CPE3403 "Not a directory.":
<http://www.ibm.com/support/knowledgecenter/api/content/ssw_ibm_i_72/apis/access.htm>
access() -- Determine File Accessibility
"...
ENOTDIR 3403 Not a directory.
..."


If I pass in a folder name that I know exists in the IFS, -1 is
returned, which means failure.

The return code issue and use of errno both were addressed already by other replies.

Can I debug the access API to see why?

Like all other [operating] system code, the answer is effectively "No, not to actually to /debug/ as in access to the debugger to see the code and variables. But there may be some tooling that could assist, such as trace and logging features."


If access is only for files, what is the best way to check if a
folder exists? Use the open API?

Already noted in other replies that "access" is appropriate for all /files/ despite the attribute might indicate that the /file/ being accessed is a directory; or that the /file/ is a *DTAARA object rather than a *FILE or *MEM [aka *MBR] or any other /object/ of the /QSYS.LIB file system under the IFS, in which both the .LIB and a [database] .FILE are effective /directory-files/ aka directories.


Here's the relevant part of the code I am trying.

DCL VAR(&PATHNULTRM) TYPE(*CHAR) LEN(513) /* Allows +
for path of 512 bytes + extra character for null +
termination. */
DCL VAR(&MODE) TYPE(*CHAR) LEN(4)
DCL VAR(&RTNVAL) TYPE(*INT) /* 0=file exists, +
-1=file does not exist */
DCL VAR(&NULL) TYPE(*CHAR) LEN(1) VALUE(X'00')

/* Check if folder for source lib exists. */
/* Call IBM API. */
/* &RTNVAL: 0=file exists, -1=file does not exist. */
CHGVAR VAR(%BIN(&MODE)) VALUE(0) /* Set access mode +
to test if the file exists - F_OK */

FWiW: Declared as Type *INT with Length 4, instead of as 4-byte *CHAR in above DCL, the &MODE can be assigned directly from a decimal value without the %BIN builtin. If a character definition must persist, then STG(*DEFINED) can be used to address the same storage as the integer type.

CHGVAR VAR(&PATHNULTRM) VALUE('/ARCHIVED_SOURCE/' +
*CAT %TRIM(&SRCLIB) *CAT &NULL)

I am not sure what is the actual generated code for the new %TRIM built-in, but the old-style *TCAT operator is quite possibly [much] more efficient. Obviously if the leading blanks for the /trimmed/ character variable must be removed, then the %TRIM is required. More likely only the trailing blanks must be removed, and then the %TRIMR is more efficient [albeit I would guess even that built-in likely is less efficient than using *TCAT].

CALLPRC PRC('access') PARM((&PATHNULTRM) (&MODE)) +
RTNVAL(&RTNVAL)

In another reply Scott suggested coding the above, instead, with "PARM((&PATHNULTRM) (&MODE *BYVAL))" while also noting the same about declaring &MODE as a four-byte *INT vs *CHAR.

/* Folder for source lib does not exist so make it. */
IF COND(&RTNVAL = -1) THEN(DO)
CHGVAR VAR(&DIR) VALUE('/ARCHIVED_SOURCE/' *CAT +
%TRIM(&SRCLIB))

Unless the value of &SRCLIB might have leading blanks that need trimming, because the full &DIR [all trailing blanks included] is the DIR() specification on the next statement, the %TRIM [or even %TRIMR] I presume should be unnecessary in the above statement.

MKDIR DIR(&DIR)

For lack of any MONMSG here, what if [the same program running in] another process effected that same MKDIR *after* the CALLPRC PRC('access') but *before* the MKDIR? The prior existence-check processing would have been for naught, and a more general\generic or a default handler would take control for the /already exists/ condition.

ENDDO


A branch of the topic thread already alluded, but I figure there is some value in noting more generically:

Typically ideal is just deferring any existence checking to the method performing the desired operation, and then handle the possible error(s) for that request; let the invoked code both deal with any concurrency issues and manifest any error conditions with an escape message. An exception is when the existence-checking is performed as a side-effect of an allocation request that will ensure prevention for negative effects from concurrent work; that is for ensuring existence however, whereas the scenario in this topic is ensuring non-existence.

Performing redundant existence-checking [work that is going to be performed again just a moment later, a few statements later,] is little more than busy-work for the system and more coding [and thus more code to test\debug] for the programmer. And any chance for concurrency would suggest that a condition of already-exists remains possible, even after an earlier existence-check; any such incident eventually encountered, might expose what was coded as a generally poor design choice.

Seems all of the above code could be reduced to just the construction of the &DIR character string data, the MKDIR request, and a MONMSG with an EXEC to remove an /already exists/ error message. All of the shown as-relevant declarative could be pared as well. So with regard to the existence of the *DIR object, coding as presumed-success of the MKDIR request and only reactively responding to any errors allows for purging all of the coding as presumed-possible-failure for the upcoming MKDIR by proactively testing for existence [originally coded with an intention of mitigating a MKDIR failure, despite that request might still fail due to the same condition that was tested-for earlier].


As an Amazon Associate we earn from qualifying purchases.

This thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.