Operating System - OpenVMS
1748089 Members
4867 Online
108758 Solutions
New Discussion ī„‚

Re: lstat and case-sensitivity

 
mpradhan
Advisor

lstat and case-sensitivity

 Hi,

I have set "SET PROCESS=/PARSE_STYLE=EXTENDED" and "SET PROCESS/CASE_LOOKUP=SENSITIVE". By doing so, I can now I have file names with two diffenent cases, e.g. FILE.TXT;1 and file.txt;1 under a directory DIR

when I use lstat([DIR]FILE.TXT) it works, but when I use lstat([DIR]file.txt) it fails with ENOENT. I can do sys$open() on both paths successfully. 

I tried setting sys$set_process_propertiesw (0, 0, PPROP$C_PARSE_STYLE_TEMP, PARSE_STYLE$C_EXTENDED, 0, 0, 0) and sys$set_process_propertiesw (0, 0, PPROP$C_CASE_LOOKUP_TEMP, PPROP$K_CASE_SENSITIVE, 0, 0, 0) but lstat() still fails. 

 

Question -

do these above set_process_propertiesw work for lstat()? 

what else should be done so that lstat() treats filenames as case-sensistive?

15 REPLIES 15
Hoff
Honored Contributor

Re: lstat and case-sensitivity

Two different files, differing only by case?   Okay.   Not something I'd recommend., but enable the DECC$EFS_CASE_PRESERVE feature, if you really want to do that.   Details are in the docs.

Steven Schweda
Honored Contributor

Re: lstat and case-sensitivity

> do these above set_process_propertiesw work for lstat()?

   Apparently not. As "HELP SET PROCESS /PARSE_STYLE" says:

        Setting a particular parse style tells DCL how it should handle
        command syntax. User programs can also examine the state of this
        setting if they need to use different parse rules.

   lstat() behavior is a CRTL question, not a DCL question, so it's the
DECC$ stuff which affects it.

mpradhan
Advisor

Re: lstat and case-sensitivity

I have tried this.

under my test directory both OUT.TXT;2 and out.txt;2 exist however only one out.txt;4 exist.

this is my test program.

#define ENABLE TRUE
#define DISABLE 0

static int set_feature_default(const char *name, int value)
{
int index = decc$feature_get_index(name);;
if (index > 0)
index = decc$feature_set_value (index, 0, value);
return index;
}
static void show_feature_default(const char* name)
{
int index = decc$feature_get_index(name);
if(index > 0)
{
int value = decc$feature_get_value(index, 0);
cout << name << " has value " << value << endl;
}
}

 

 

int
main(int argc, char** argv)
{
string sFilePath;
cout << "Enter Path: ";
cin >> sFilePath;
struct stat st;
int iRet(0);

int iCaseSensitive(0);
cout << "Case Sensitive (1/0): ";
cin >> iCaseSensitive;
if(iCaseSensitive)
{
int prev_value = set_feature_default("DECC$ARGV_PARSE_STYLE", ENABLE);
if(0 != prev_value)
cout << "Failed to set DECC$ARGV_PARSE_STYLE," << " errno=" << strerror(errno) << endl;
prev_value = set_feature_default("DECC$EFS_CASE_PRESERVE", ENABLE);
if(0 != prev_value)
cout << "Failed to set DECC$EFS_CASE_PRESERVE," << " errno=" << strerror(errno) << endl;
}
show_feature_default("DECC$ARGV_PARSE_STYLE");
show_feature_default("DECC$EFS_CASE_PRESERVE");
//decc$feature_show_all();

if((iRet = lstat(sFilePath.c_str(), &st)) < 0)
{
cout << "lstat(" << sFilePath << ") failed, error=" << strerror(errno) << endl;
}
else
cout << "lstat(" << sFilePath << ") OK" << endl;
exit(0);
}

 

when I run this on OUT.TXT;2 or out.txt;2, it does not matter what case-sensitivity is set to, lstat works.

$ test_stat
Enter Path: dka0:[ssq]out.txt;2
Case Sensitive (1/0): 1 
DECC$ARGV_PARSE_STYLE has value 1
DECC$EFS_CASE_PRESERVE has value 1
lstat(dka0:[ssq]out.txt;2) OK
$ test_stat
Enter Path: dka0:[ssq]OUT.TXT;2
Case Sensitive (1/0): 1
DECC$ARGV_PARSE_STYLE has value 1
DECC$EFS_CASE_PRESERVE has value 1
lstat(dka0:[ssq]OUT.TXT;2) OK
$ test_stat
Enter Path: dka0:[ssq]out.txt;2
Case Sensitive (1/0): 0
DECC$ARGV_PARSE_STYLE has value 0
DECC$EFS_CASE_PRESERVE has value 0
lstat(dka0:[ssq]out.txt;2) OK
$ test_stat
Enter Path: dka0:[ssq]OUT.TXT;2
Case Sensitive (1/0): 0
DECC$ARGV_PARSE_STYLE has value 0
DECC$EFS_CASE_PRESERVE has value 0
lstat(dka0:[ssq]OUT.TXT;2) OK

 

but when I run this with out.txt;3, it does not matter what settings I have for case-sensitive, it always fails with ENOENT

$ test_stat
Enter Path: dka0:[ssq]out.txt;4
Case Sensitive (1/0): 1
DECC$ARGV_PARSE_STYLE has value 1
DECC$EFS_CASE_PRESERVE has value 1
lstat(dka0:[ssq]out.txt;4) failed, error=no such file or directory
$ test_stat
Enter Path: dka0:[ssq]out.txt;4
Case Sensitive (1/0): 0
DECC$ARGV_PARSE_STYLE has value 0
DECC$EFS_CASE_PRESERVE has value 0
lstat(dka0:[ssq]out.txt;4) failed, error=no such file or directory

 

I am doing somethign wrong?

 

Steven Schweda
Honored Contributor

Re: lstat and case-sensitivity

> main(int argc, char** argv)
> {
> [...]
> int prev_value = set_feature_default("DECC$ARGV_PARSE_STYLE", ENABLE);

   Too late.

      http://h71000.www7.hp.com/doc/83final/5763/5763pro_004.html

[...]
DECC$ARGV_PARSE_STYLE
With DECC$ARGV_PARSE_STYLE enabled, case is preserved in command-line
arguments when the process has been set up for extended DCL parsing
using SET PROCESS/PARSE_STYLE=EXTENDED.

DECC$ARGV_PARSE_STYLE must be defined externally as a logical name or
set in a function called using the LIB$INITIALIZE mechanism because it
is evaluated before function main is called.
[...]

    But I don't see you doing anything with argv[], so this may only
waste time (and brain-space) without affecting the result.

> under my test directory both OUT.TXT;2 and out.txt;2 exist however
> only one out.txt;4 exist.

   I would trust actual DIRECTORY output more than your description of
DIRECTORY output, especially when I see things like the following:

> but when I run this with out.txt;3, it does not matter what settings I
> have for case-sensitive, it always fails with ENOENT
>
> $ test_stat
> Enter Path: dka0:[ssq]out.txt;4

Hoff
Honored Contributor

Re: lstat and case-sensitivity

If this code is ever going to be transferred off of this OpenVMS server and used on other and end-user servers, then this full-on case-sensitivity approach is a really bad idea, and this almost certainly will cause problems and problem reports.   That even once this code is working.   Very few OpenVMS systems have case sensitivity enabled, and most OpenVMS software does not expect this and has not been tested with this.    Officially and per the HPE folks: "HP strongly recommends that you use caution when enabling case sensitivity in your processes."

As for your question, this is typically a UNIX-oriented configuration, so you'll likely want to avoid version support.   Quite possibly also OpenVMS filename processing, and use UNIX naming. Or set the UNIX compatibility level to a much higher value.   That UNIX level controls the settings of a group of features.  More than a little of this is experimentation, based on your local requirements and expectations, and the particular character set in use for the filenames.

That you're possibly working with symbolic links (as lstat expressly supports) also likely means a trip through the related OpenVMS documentation and recent patches, as there are some wrinkles in this area ā€” there was link support added into the last OpenVMS version or two, and it's potentially going to be a little different setup than what might be expected by a UNIX or Linux or BSD developer.

That posted C++ code appears incomplete, too.   23 errors result from a direct compilation.   I also can't tell which files are present in your test configuration.    If you want us to look at the C++ code, please attach the complete C++ code and the associated build procedure; enough details that I might reproduce this, and test it here.   I didn't bother troubleshooting that C++ code, and wrote a simpler C reproducer with rather fewer knobs.

I'm testing with a somewhat shorter example, get what I expect to see with case sensitivity enabled.  (But I don't yet know what files exist in your configuration.)

#include <stat.h>

#include <stdio.h>

#include <stdlib.h>

#include  <string.h>

 

int

main(int argc, char** argv) {

  struct stat statbuf;

  int RetStat;

  if ( argc != 2 )

     return EXIT_FAILURE;

  RetStat = lstat( argv[1], &statbuf );

  if ( RetStat )

    strerror( RetStat );

  return EXIT_SUCCESS;  

}

And things seem to work as expected with a couple of test files on a scratch LD disk set for ODS-5.

Rough sequence used follows...

ld create filespec/size=8192

ld connect filespec LDA256

init LDA256: scratch/STRUCT=5

mount LDA256: scratch

DEFINE DECC$EFS_CASE_PRESERVE TRUE

CC X/DEBUG/NOOPT

LINK X/DEBUG/NOOPT

set process/parse=extended/case=sens

create LDA256:[000000]TEST.TMP

create LDA256:[000000]test.tmp

X LDA256:[000000]TEST.TMP

X LDA256:[000000]test.tmp

etc.

 

But as mentioned above, please attach full source code and enough that somebody here can reproduce the reported behavior.

mpradhan
Advisor

Re: lstat and case-sensitivity

the only piece that was missing from the code was header, here are they.

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <errno.h>
#include <unixlib.h>

// VMS Headers
#include <atrdef.h>
#include <descrip.h>
//#include "fatdef.h"
#include <rms>
#include <starlet>
#include <ssdef.h>
#include <descrip.h>
#include <fabdef.h>

#include <descrip.h>
#include <atrdef.h>
#include <ppropdef.h>
#include <fibdef.h>
#include <iodef.h>
#include <sbkdef.h>
//#include "vmstime.h"

typedef struct fibdef FIB;
//#include "fatdef.h"
#include "sys$examples:bapidef.h"

 

This is a purely VMS test.

As noted above setting these dec$* looks to be too late, this has a code http://antinode.info/ftp/cdrtools/cdrtools-2_01_01a11/libvms/vms_init.c. But I cannot link this code it keeps complaing about undefined lib$initialize.

Anyways. 

One interesting thing that I saw while doing this is. when I use lstat and print time-stamps, those donot match to what dir /full will print (ctime and mtime/atime are swapped). lstat even reports ctime < mtime, which is weird. 

int
main(int argc, char** argv)
{
string sFilePath;
cout << "Enter Path: ";
cin >> sFilePath;
struct stat st;

int iNewCode(false);
cout << "use mystat(1/0): ";
cin >> iNewCode;
if(!iNewCode)
{
if((iRet = lstat(sFilePath.c_str(), &st)) < 0)
{
cout << "lstat(" << sFilePath << ") failed, error=" << strerror(errno) << endl;
}
else
{
cout << "lstat(" << sFilePath << ") OK" << endl;
cout << "ctime: " << st.st_ctime << " mtime: " << st.st_mtime << " atime: " << st.st_atime << " size: " << st.st_size << " mode: " << st.st_mode << endl;
}
}
else
my_stat(sFilePath.c_str());

exit(0);
}

 

$ test_stat
Enter Path: dka0:[ssq]out.txt;2
DECC$ARGV_PARSE_STYLE has value 0
DECC$EFS_CASE_PRESERVE has value 0
use mystat(1/0): 0
lstat(dka0:[ssq]out.txt;2) OK
ctime: 1337117482 mtime: 1337117572 atime: 1337117572 size: 1018 mode: 33256

$ dir /full dka0:[ssq]out.txt;2

Directory DKA0:[SSQ]

OUT.TXT;2 File ID: (19005,4,0)
Size: 2/32 Owner: [SYSTEM]
Created: 15-MAY-2012 17:31:22.29
Revised: 15-MAY-2012 17:32:52.87 (1)
Expires: 10-MAR-2017 14:07:20.31
Backup: <No backup recorded>
Effective: <None specified>
Recording: <None specified>
Accessed: 15-MAY-2012 17:31:22.29
Attributes: 15-MAY-2012 17:32:52.87
Modified: 15-MAY-2012 17:31:22.29
Linkcount: 1
File organization: Sequential
Shelved state: Online
Caching attribute: Writethrough
File attributes: Allocation: 32, Extend: 0, Global buffer count: 0
Version limit: 3
Record format: VFC, 2 byte header, maximum 0 bytes, longest 107 bytes
Record attributes: Print file carriage control
RMS attributes: None
Journaling enabled: None
File protection: System:RWED, Owner:RWED, Group:RE, World:
Access Cntrl List: (IDENTIFIER=[150,*],ACCESS=READ)
Client attributes: None

Total of 1 file, 2/32 blocks.

 

convert above time-stamps (ones from lstat) to EST

to me looks like lstat() has a bug in this regard, or may be I am hallucinating

mpradhan
Advisor

Re: lstat and case-sensitivity

actual directory output

 

$ dir dka0:[ssq]

Directory DKA0:[SSQ]

OUT.SAV;1 out.t;1 OUT.TXT;3 OUT.TXT;2
OUT.TXT;1 out.txt;4 out.txt;3 out.txt;2
OUT_ORIG.SAV;1 out_rest.sav;1 OUT_RESTORE.TXT;1 RESTORE.TXT;1
TESTIDX.ISM;1 This_file^_is_not_OK.txt;1
This_file^%is_not_OK.txt;1 This_file^+is_not_OK.txt;1
This_file^.is_OK.txt;1 This_file^=is_not_OK.txt;1

Total of 18 files.
$

H.Becker
Honored Contributor

Re: lstat and case-sensitivity

>>> As noted above setting these dec$* looks to be too late, this has a code http://antinode.info/ftp/cdrtools/cdrtools-2_01_01a11/libvms/vms_init.c. But I cannot link this code it keeps complaing about undefined lib$initialize.

LIB$INITIALIZE is in SYS$COMMON:[SYSLIB]STARLET.OLB, which the linker processes by default. You may want to show the full link command and the exact linker message. 

Steven Schweda
Honored Contributor

Re: lstat and case-sensitivity

> As noted above setting these dec$* looks to be too late, this has a
> code http://antinode.info/ftp/cdrtools/cdrtools-2_01_01a11/libvms/vms_init.c.
> But I cannot link this code it keeps complaing about undefined
> lib$initialize.

   That's C code, not C++, and I can't see how you're trying to use it.
(There's more, similar code in Zip and UnZip, if you're looking for more
C examples, by the way.  But if I did it, it probably looks very
similar.)

   "I cannot" is not a useful problem description. It does not say what
you did. It does not say what happened when you did it.  As usual,
showing actual commands with their actual output can be more helpful
than vague descriptions or interpretations.

   LIB$INITIALIZE is easier to use in C (where I have done it) than in
C++ (where I haven't done it).  But if you do not use argv[], then who
cares about DECC$ARGV_PARSE_STYLE?  (Other such things can be set later,
so you wouldn't need LIB$INITIALIZE for them, only for
DECC$ARGV_PARSE_STYLE.)

    If you _were_ using argv[], then the easy way to test
DECC$ARGV_PARSE_STYLE would be to define the logical name, and forget
about trying to do it in your program (until you determine that you
really need to use it).