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.