Search code examples
fopenfile-renamemainframezos

rename file when using DD name


In a 'C' language LP64 compiled program, which will run in Batch, TSO and z/OS UNIX, when opening a PDS(E) member using the following notation (recommended in order to allow file disposition to be used):-

hFile = fopen("DD:CONFIG(COPY)", "w");
fclose(hFile);

I am surprised to discover that the following does not appear to work:-

rename("DD:CONFIG(COPY)","DD:CONFIG(MAIN)");

Failing as it does with an errno of ENOENT (EDC5129I No such file or directory.)

The documentation for rename says:-

The rename() function renames memory files and DASD data sets. It also renames individual members of PDSs (and PDSEs)

If instead I do:-

rename("//'MYUSER.CONFIG(COPY)'","//'MYUSER.CONFIG(MAIN)'");

the rename() works.

Alternatively if I do:-

rename("//'MYUSER.CONFIG(COPY)'","DD:CONFIG(MAIN)");

if fails with an errno of EINVAL (EDC5121I Invalid argument.)

Why does it not accept the same file name notation that is used for fopen?

The reason this is important is because the rename() cannot succeed while the PDSE is being browsed by someone. Whereas, using the DD: notation allows an fopen() for write to succeed when the PDSE is being browsed because the DISP=SHR coded on the DD name in the JCL is adopted by the fopen().

So, I suppose the real question is - how can my program rename a PDSE member in a way that will succeed when the PDSE is also being browsed by someone?


Solution

  • The technique required to rename a dataset is different than the technique to rename a member inside a PDS/PDSE...I'd wager that the system rename() function you're calling is just getting this wrong. In z/OS, there are lots of combinations functions like "rename()" have to handle, and it's not unusual to find some that don't work as you expect.

    Certainly it's worth a call to IBM Support to see if there's something else going on here...what you're trying to do seems like it should work, so I think there's something to be said for treating it like a bug or documentation error.

    Beyond that, as you suggest, you can either use the form of rename that works, or you can replace the system's rename function with something that actually works properly.

    One simple way would be to create the rename() as you show it:

    rename("//'MYUSER.CONFIG(COPY)'","//'MYUSER.CONFIG(MAIN)'");
    

    You can get the DSN for a DDNAME using the fldata() function, so it's not hard to create a rename like this on the fly given an open file handle. Beware that the form of rename may allocate the file you specify with DISP=OLD, and hence cause problems if some other task has the file allocated. Also, if this is supposed to be commercial quality code, as a customer, my eyebrows would go up if I found out you needed to launch some external program because you couldn't figure out how to rename a PDS/PDSE member - but that might just be me.

    The other alternative is to write your own "rename()" function...unfortunately, it most likely would need to be assembler language if you want it to be efficient. As others suggest, you might spawn off a shell, REXX or TSO command, but of course, that means creating a new process, etc etc etc just to rename the PDS/PDSE member. Keep in mind also that some of these approaches might also have issues with trying to allocate the input file with DISP=OLD.

    If that's too slow for your needs, the way to do what you want is to call a small assembler routine that invokes the system STOW service against your DDNAME to do your rename. The flow would be something like this:

    1. You'd create a 16-byte area containing the old and new member names. They're 8 characters each and blank padded.

    2. You'd need the address of an open DCB that describes the file you're looking at. You can get the DCB address from the FILE structure, I believe - or you could just open a second DCB to the DDNAME you have allocated.

    3. You'd call the system STOW service with the parameters that tell it to rename a PDS/PDSE member:

      STOW dcb,area_from_step1,C

    In the STOW macro above, the "directory option" of "C" tells STOW that you want to rename an existing member. The area_from_step1 has the current and new member names - the system searches the directory for the current name and rewrites it with the new member name in place.

    To be honest, what I describe above is exactly what the system runtime should be doing, but if it's not and IBM doesn't want to fix it, then you might prefer to do this sort of thing "by hand".