-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AIX/IBM i support #133
Open
NattyNarwhal
wants to merge
8
commits into
parcel-bundler:master
Choose a base branch
from
NattyNarwhal:aix
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
AIX/IBM i support #133
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
e0c2189
Add AIX/i to build
NattyNarwhal 265ac37
WIP: import IBM's *at shims
NattyNarwhal 32f202c
Fix link issue on AIX (need threaded C++ lib)
NattyNarwhal b1fe594
fix -fpermissive
NattyNarwhal 5d517fe
We don't need d_type if we did a stat
NattyNarwhal 45d9926
silly me forgot to fix the other -fpermissive
NattyNarwhal dc4b897
try to move shims to separate file
NattyNarwhal a58970d
Fix typo
NattyNarwhal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,362 @@ | ||
#ifdef __PASE__ | ||
/* | ||
* IBM i has defective *at functions (only supports AT_FDCWD). These shims were | ||
* provided to me from IBM, developed for some other software. | ||
* | ||
* The shim had openat, unlinkat, and renameat. We need openat and fstatat, so | ||
* the shim has been modified to provide this set of functions. | ||
* | ||
* These were also provided to me so that they could be relicensed under the | ||
* same license that Watcher is under. | ||
* | ||
* Copyright (c) 2022-2023 IBM Corporation | ||
*/ | ||
|
||
/* This code begins */ | ||
/* */ | ||
/* File............: atfuncs.cinc */ | ||
/* Purpose.........: Provide PASE for i alternative functions for unlinkat1, openat, and renameat.*/ | ||
/* */ | ||
/* Usage Notes.....: These functions work in the following way: */ | ||
/* (1) If the path is absolute (i.e. starts with '/'), pass the parameters to */ | ||
/* the non-alternative function (i.e. openat2 -> open, etc.). */ | ||
/* (2) If the 'AT_FDCWD' flag is specified as the directory file descriptor, */ | ||
/* pass the parameters to the non-alternative function. This usage */ | ||
/* relies on underlying support for relative paths in the non-alternative */ | ||
/* functions. Note that for renameat, both files descriptors must be */ | ||
/* supplied the 'AT_FDCWD' flag to perform this usage. */ | ||
/* (3) For openat and unlinkat, if neither (1) or (2) are performed, then */ | ||
/* the process's current working directory is generated, and then changed */ | ||
/* to the supplied directory file descriptor and the non-alternative */ | ||
/* function is called using relative pathnames like (2). For renameat, */ | ||
/* the current working directory is generated. For renameat, if a valid */ | ||
/* (i.e. not 'AT_FDCWD') is directory file descriptor is supplied, an */ | ||
/* absolute file path is generated for that filename. */ | ||
|
||
#include <fcntl.h> | ||
#include <errno.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/stat.h> | ||
#include <limits.h> | ||
#include <dirent.h> | ||
|
||
/* Function.......: getcwdpath */ | ||
/* Purpose........: This function will get the current working directory up to the maximum */ | ||
/* pathname length. */ | ||
/* */ | ||
/* Inputs.........: const char *, unsigned int, char **, int * */ | ||
/* */ | ||
/* buf1(output)....: A pointer to a character buffer that that the current working directory */ | ||
/* MAY be placed in. The buffer pointer to is typically allocated from stack */ | ||
/* storage. */ | ||
/* buf1Size(input): The size in bytes of buf1. */ | ||
/* buf2(output)...: A pointer to a pointer to a character buffer that MAY point to allocated */ | ||
/* storage during this function invocation. The allocated storage will be from */ | ||
/* the heap storage. The caller is responsible to free this storage. */ | ||
/* cwdPathLoc(output): A pointer to an integer which determines where the current working */ | ||
/* directory output was placed. */ | ||
/* The integer has the following possible values: */ | ||
/* 0 - the output was placed in buf1. */ | ||
/* 1 - the output was placed in buf2. This storage was malloc'd and must */ | ||
/* be freed by the caller. */ | ||
/* */ | ||
/* Return Value....: 0 - success */ | ||
/* -1 - failure, check errno for more information */ | ||
/* */ | ||
/* Notes...........: None */ | ||
int getcwdpath(const char * buf1, unsigned int buf1Size, | ||
char ** buf2, unsigned int * cwdPathLoc) | ||
{ | ||
if((buf1 == (const char *)NULL) || /* safety/sanity check */ | ||
(cwdPathLoc == (unsigned int *)NULL)) | ||
{ | ||
errno = EINVAL; | ||
return -1; | ||
} | ||
|
||
int curpathrc = 0; /* default to success. */ | ||
*cwdPathLoc = 0; /* default to passed in buffer. */ | ||
|
||
/* first try to get the cwd path using the supplied buffer */ | ||
if(getcwd((char *)buf1, buf1Size) == NULL) | ||
{ | ||
/* failed to get the current working directory. */ | ||
/* check if the failure was because the input buffer was too small. */ | ||
|
||
/* Note that this code exists, but apparently AIX's PATH_MAX limit */ | ||
/* is 512 bytes which is below the 4096 that is used for the stack */ | ||
/* buffer in the at-functions. This code will never be executed on */ | ||
/* AIX. See IBM Documenation for AIX 7.3 for the limits.h header */ | ||
/* for more information: */ | ||
/* https://www.ibm.com/docs/en/aix/7.3?topic=files-limitsh-file */ | ||
|
||
if((errno == ERANGE) || | ||
(errno == E2BIG)) | ||
{ | ||
unsigned int buf2Size = buf1Size; | ||
char * bp = NULL; | ||
do | ||
{ | ||
buf2Size *= 2; /* double the buffer size */ | ||
if(buf2Size > PATH_MAX) /* if the buffer size is above */ | ||
buf2Size = PATH_MAX; /* the max, set size to max */ | ||
|
||
if(bp != NULL) | ||
free((void *)bp); /* free previous buffer */ | ||
|
||
bp = (char *)malloc(buf2Size); /* malloc new storage */ | ||
if(bp == NULL) | ||
{ | ||
/* errno will be set by malloc() failure. */ | ||
/* Nothing was malloc'd so nothing to free before returning. */ | ||
curpathrc = -1; | ||
break; | ||
} | ||
/* loop while: */ | ||
/* getcwd() fails with errno ERANGE or E2BIG, and the current */ | ||
/* size of the buffer is less than the max path length. */ | ||
} while((getcwd(bp, buf2Size) != NULL) && | ||
((errno == ERANGE) || (errno == E2BIG)) && | ||
(buf2Size < PATH_MAX)); | ||
|
||
*buf2 = bp; /* set output buffer to newly malloc'd space */ | ||
*cwdPathLoc = 1; /* set output indicator */ | ||
} | ||
else | ||
{ | ||
/* getcwd() didn't fail because the buffer was too small. */ | ||
/* errno will be set by getcwd() failure. */ | ||
curpathrc = -1; | ||
} | ||
} | ||
/* else */ | ||
/* all the work was done by the call to cwd, and the output should */ | ||
/* be in buf1. */ | ||
|
||
return curpathrc; | ||
} | ||
|
||
int ibmi_fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags) | ||
{ | ||
int _fstatrc = -1; /* default to fail */ | ||
const unsigned int cwdBufSize = 4096; /* cwd init buffer size */ | ||
char cwdbuf[cwdBufSize]; /* cwd init buffer */ | ||
char ** cwdpath = NULL; /* cwd malloc'd path */ | ||
unsigned int cwdPathLoc = 0; /* cwd path location */ | ||
|
||
/* AT_SYMLINK_NOFOLLOW indicates if lstat or stat */ | ||
int (*underfunc)(const char *, struct stat *) = NULL; | ||
|
||
if(pathname == (const char *)NULL) /* safety/sanity check */ | ||
{ | ||
errno = EINVAL; | ||
return -1; | ||
} | ||
|
||
if(flags & AT_SYMLINK_NOFOLLOW) /* stat on a symbolic link */ | ||
underfunc = lstat; | ||
else /* stat on a file */ | ||
underfunc = stat; | ||
|
||
/* path is absolute, stat it. */ | ||
if(*pathname == '/') | ||
return underfunc(pathname, statbuf); | ||
|
||
/* path is relative, stat in current working directory of process. */ | ||
if(dirfd == AT_FDCWD) | ||
return underfunc(pathname, statbuf); | ||
|
||
/* path is relative, but caller doesn't want to use process's current */ | ||
/* working directory. Build the current working directory, so it */ | ||
/* can be changed back to. */ | ||
_fstatrc = getcwdpath((const char *)&cwdbuf, cwdBufSize, | ||
cwdpath, &cwdPathLoc); | ||
|
||
if(_fstatrc == -1) | ||
{ | ||
/* errno will be set by getcwdpath() failure. */ | ||
_fstatrc = -1; | ||
goto leave; | ||
} | ||
|
||
/* path is relative, change process's current working directory to */ | ||
/* the directory file descriptor. */ | ||
if(fchdir(dirfd) == -1) | ||
{ | ||
/* errno will be set by fchdir() failure. */ | ||
_fstatrc = -1; | ||
goto leave; | ||
} | ||
|
||
_fstatrc = underfunc(pathname, statbuf); | ||
|
||
/* change working directory back to original process's working */ | ||
/* directory. */ | ||
if(cwdPathLoc == 0) | ||
{ | ||
if(chdir(cwdbuf) == -1) | ||
{ | ||
/* errno will be set by chdir() failure. */ | ||
_fstatrc = -1; | ||
} | ||
} | ||
else | ||
{ | ||
if(chdir(*cwdpath) == -1) | ||
{ | ||
/* errno will be set by chdir() failure. */ | ||
_fstatrc = -1; | ||
} | ||
} | ||
|
||
leave: | ||
if(*cwdpath != NULL) /* if malloc'd storage, free it now. */ | ||
free(*cwdpath); | ||
|
||
return _fstatrc; | ||
} | ||
|
||
int ibmi_openat(int dirfd, const char *pathname, int flags) | ||
{ | ||
int _openrc = -1; /* default to fail */ | ||
const unsigned int cwdBufSize = 4096; /* cwd init buffer size */ | ||
char cwdbuf[cwdBufSize]; /* cwd init buffer */ | ||
char ** cwdpath = NULL; /* cwd malloc'd path */ | ||
unsigned int cwdPathLoc = 0; /* cwd path location */ | ||
|
||
if(pathname == (const char *)NULL) /* safety/sanity check */ | ||
{ | ||
errno = EINVAL; | ||
return -1; | ||
} | ||
|
||
/* path is absolute, open it. */ | ||
if(*pathname == '/') | ||
return open(pathname, flags); | ||
|
||
/* path is relative, open in current working directory of process. */ | ||
if(dirfd == AT_FDCWD) | ||
return open(pathname, flags); | ||
|
||
/* path is relative, but caller doesn't want to use process's current */ | ||
/* working directory. Build the current working directory, so it */ | ||
/* can be changed back to. */ | ||
_openrc = getcwdpath((const char *)&cwdbuf, cwdBufSize, | ||
cwdpath, &cwdPathLoc); | ||
|
||
if(_openrc == -1) | ||
{ | ||
/* errno will be set by getcwdpath() failure. */ | ||
return -1; | ||
} | ||
|
||
/* path is relative, change process's current working directory to */ | ||
/* the directory file descriptor. */ | ||
if(fchdir(dirfd) == -1) | ||
{ | ||
_openrc = -1; | ||
goto leave; | ||
} | ||
|
||
/* path is relative, open it relative to directory file descriptor. */ | ||
_openrc = open(pathname, flags); | ||
|
||
/* change working directory back to original process's working */ | ||
/* directory. */ | ||
if(cwdPathLoc == 0) | ||
{ | ||
if(chdir(cwdbuf) == -1) | ||
{ | ||
/* errno will be set by chdir() failure. */ | ||
_openrc = -1; | ||
} | ||
} | ||
else | ||
{ | ||
if(chdir(*cwdpath) == -1) | ||
{ | ||
/* errno will be set by chdir() failure. */ | ||
_openrc = -1; | ||
} | ||
} | ||
|
||
leave: | ||
if(*cwdpath != NULL) /* if malloc'd storage, free it now. */ | ||
free(*cwdpath); | ||
|
||
return _openrc; | ||
} | ||
|
||
int ibmi_openat2(int dirfd, const char * pathname, int flags, mode_t mode) | ||
{ | ||
int _openrc = -1; /* default to fail */ | ||
const unsigned int cwdBufSize = 4096; /* cwd init buffer size */ | ||
char cwdbuf[cwdBufSize]; /* cwd init buffer */ | ||
char ** cwdpath = NULL; /* cwd malloc'd path */ | ||
unsigned int cwdPathLoc = 0; /* cwd path location */ | ||
|
||
if(pathname == (const char *)NULL) /* safety/sanity check */ | ||
{ | ||
errno = EINVAL; | ||
return -1; | ||
} | ||
|
||
/* path is absolute, open it. */ | ||
if(*pathname == '/') | ||
return open(pathname, flags, mode); | ||
|
||
/* path is relative, open in current working directory of process. */ | ||
if(dirfd == AT_FDCWD) | ||
return open(pathname, flags, mode); | ||
|
||
/* path is relative, but caller doesn't want to use process's current */ | ||
/* working directory. Build the current working directory, so it */ | ||
/* can be changed back to. */ | ||
_openrc = getcwdpath((const char *)&cwdbuf, cwdBufSize, | ||
cwdpath, &cwdPathLoc); | ||
|
||
if(_openrc == -1) | ||
{ | ||
/* errno will be set by getcwdpath() failure. */ | ||
return -1; | ||
} | ||
|
||
/* path is relative, change process's current working directory to */ | ||
/* the directory file descriptor. */ | ||
if(fchdir(dirfd) == -1) | ||
{ | ||
_openrc = -1; | ||
goto leave; | ||
} | ||
|
||
/* path is relative, open it relative to directory file descriptor. */ | ||
_openrc = open(pathname, flags, mode); | ||
|
||
/* change working directory back to original process's working */ | ||
/* directory. */ | ||
if(cwdPathLoc == 0) | ||
{ | ||
if(chdir(cwdbuf) == -1) | ||
{ | ||
/* errno will be set by chdir() failure. */ | ||
_openrc = -1; | ||
} | ||
} | ||
else | ||
{ | ||
if(chdir(*cwdpath) == -1) | ||
{ | ||
/* errno will be set by chdir() failure. */ | ||
_openrc = -1; | ||
} | ||
} | ||
|
||
leave: | ||
if(*cwdpath != NULL) /* if malloc'd storage, free it now. */ | ||
free(*cwdpath); | ||
|
||
return _openrc; | ||
} | ||
#endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for the slow response on this PR.
One problem is that I don't think watchman is supported on AIX or OS400. There is also no inotify support as far as I can tell (I don't have access to a system to test this). Without either of those, this module isn't very useful (can't actually watch files). Do you know if these OSes have another file watching mechanism?
I'm also somewhat concerned about adding these as I have no way of testing or providing precompiled builds for these platforms. Do you have access to such a system to test with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for the late response.
Watchman isn't supported, but I didn't disable it, because Watchman is an external tool - I was thinking that it might support it or an alternative with a compatible interface might. It might be a good idea to disable it though.
It's using the "legacy" backend which is brute force; AFAIK there is no watching API, but I might be wrong. I can ask my contacts at IBM.
I understand the concerns about not being able to test things. I do have access to a system for testing. FWIW not having a binary build is OK; the user I'm doing this for is already used to having the dev toolchain to build native parts already.
(FWIW, the motivation to upstream this was things depending on watcher being extremely common in some ecosystems. Finding and patching every dependency to pull a patched copy was too onerous.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Putting a ping out here - would like to know if the above is still blocking.