ret = AFPERR_NOOBJ;
if (access & OPENACC_WR) {
/* try opening in read-write mode */
- if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDWR) < 0) {
+ if (ad_open(ofork->of_ad, upath,
+ adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
switch ( errno ) {
case EROFS:
ret = AFPERR_VLOCK;
case ENOENT:
if (fork == OPENFORK_DATA) {
/* try to open only the data fork */
- if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDWR) < 0) {
+ if (ad_open(ofork->of_ad, upath,
+ ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
goto openfork_err;
}
adflags = ADFLAGS_DF;
} else {
/* here's the deal. we only try to create the resource
* fork if the user wants to open it for write acess. */
- if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) < 0)
+ if (ad_open(ofork->of_ad, upath,
+ adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
goto openfork_err;
ofork->of_flags |= AFPFORK_OPEN;
}
} else {
/* try opening in read-only mode */
ret = AFPERR_NOOBJ;
- if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY) < 0) {
+ /* we need w access for setting deny mode fcntl excl lock */
+ if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
switch ( errno ) {
case EROFS:
ret = AFPERR_VLOCK;
+ goto openfork_err;
case EACCES:
goto openfork_err;
- break;
case ENOENT:
/* see if client asked for a read only data fork */
if (fork == OPENFORK_DATA) {
- if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY) < 0) {
+ if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
goto openfork_err;
}
adflags = ADFLAGS_DF;
#define ADFLAGS_DIR (1<<3)
#define ADFLAGS_NOHF (1<<4) /* not an error if no ressource fork */
#define ADFLAGS_CHECK_OF (1<<6) /* check for open forks from us and other afpd's */
-
-#define ADFLAGS_RDWR (1<<7) /* open read/write */
-#define ADFLAGS_RDONLY (1<<8) /* open read only */
-#define ADFLAGS_CREATE (1<<9) /* create file, open called with O_CREAT */
-#define ADFLAGS_EXCL (1<<10) /* exclusive open, open called with O_EXCL */
-#define ADFLAGS_TRUNC (1<<11) /* truncate, open called with O_TRUNC */
+#define ADFLAGS_SETSHRMD (1<<7) /* setting share mode must be done with excl fcnt lock,
+ which implies that the file must be openend rw.
+ If it can't be opened rw (eg EPERM or EROFS) it will
+ be opened ro and the fcntl locks will be shared, that
+ at least prevent other users who have rw access to the
+ file from placing excl locks. */
+#define ADFLAGS_RDWR (1<<8) /* open read/write */
+#define ADFLAGS_RDONLY (1<<9) /* open read only */
+#define ADFLAGS_CREATE (1<<10) /* create file, open called with O_CREAT */
+#define ADFLAGS_EXCL (1<<11) /* exclusive open, open called with O_EXCL */
+#define ADFLAGS_TRUNC (1<<12) /* truncate, open called with O_TRUNC */
#define ADVOL_NODEV (1 << 0)
#define ADVOL_CACHE (1 << 1)
if (adflags & ADFLAGS_RDWR)
oflags |= O_RDWR;
- if (adflags & ADFLAGS_RDONLY)
+ if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_SETSHRMD))
+ oflags |= O_RDWR;
+ else
oflags |= O_RDONLY;
if (adflags & ADFLAGS_CREATE)
oflags |= O_CREAT;
ad->ad_data_fork.adf_fd = open(path, oflags, admode);
if (ad->ad_data_fork.adf_fd == -1) {
- if (errno != OPEN_NOFOLLOW_ERRNO)
+ switch (errno) {
+ case EPERM:
+ case EROFS:
+ if ((adflags & ADFLAGS_SETSHRMD) && (adflags & ADFLAGS_RDONLY)) {
+ oflags &= ~O_RDWR;
+ oflags |= O_RDONLY;
+ if ((ad->ad_data_fork.adf_fd = open(path, oflags, admode)) == -1)
+ return -1;
+ break;
+ }
return -1;
-
- ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
- if ((lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN)) <= 0) {
- free(ad->ad_data_fork.adf_syml);
+ case OPEN_NOFOLLOW_ERRNO:
+ ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
+ if ((lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN)) <= 0) {
+ free(ad->ad_data_fork.adf_syml);
+ return -1;
+ }
+ ad->ad_data_fork.adf_syml[lsz] = 0;
+ ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
+ break;
+ default:
return -1;
}
- ad->ad_data_fork.adf_syml[lsz] = 0;
- ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
}
if (!st_invalid)
ad_p = ad->ad_ops->ad_path(path, adflags);
oflags = O_NOFOLLOW | ad2openflags(adflags);
nocreatflags = oflags & ~(O_CREAT | O_EXCL);
+
ad->ad_mdp->adf_fd = open(ad_p, nocreatflags);
- if ( ad->ad_mdp->adf_fd < 0 ) {
- if (!(errno == ENOENT && (oflags & O_CREAT)))
- return ad_error(ad, adflags);
- /*
- * We're expecting to create a new adouble header file here
- * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
- */
- LOG(log_debug, logtype_default, "ad_open(\"%s\"): creating adouble file",
- fullpathname(path));
- admode = mode;
- errno = 0;
- st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
- if ((ad->ad_options & ADVOL_UNIXPRIV))
- admode = mode;
- admode = ad_hf_mode(admode);
- if (errno == ENOENT) {
- if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
- return ad_error(ad, adflags);
+ if (ad->ad_mdp->adf_fd < 0) {
+ switch (errno) {
+ case EPERM:
+ case EROFS:
+ if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_SETSHRMD)) {
+ nocreatflags &= ~O_RDWR;
+ nocreatflags |= O_RDONLY;
+ if ((ad->ad_mdp->adf_fd = open(ad_p, nocreatflags)) == -1)
+ return -1;
+ break;
}
+ return -1;
+ case ENOENT:
+ if (!(oflags & O_CREAT))
+ return ad_error(ad, adflags);
+ /*
+ * We're expecting to create a new adouble header file here
+ * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
+ */
+ LOG(log_debug, logtype_default, "ad_open(\"%s\"): creating adouble file",
+ fullpathname(path));
admode = mode;
+ errno = 0;
st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
if ((ad->ad_options & ADVOL_UNIXPRIV))
admode = mode;
admode = ad_hf_mode(admode);
- }
+ if (errno == ENOENT) {
+ if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
+ return ad_error(ad, adflags);
+ }
+ admode = mode;
+ st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
+ if ((ad->ad_options & ADVOL_UNIXPRIV))
+ admode = mode;
+ admode = ad_hf_mode(admode);
+ }
- /* retry with O_CREAT */
- ad->ad_mdp->adf_fd = open(ad_p, oflags, admode);
- if ( ad->ad_mdp->adf_fd < 0 )
- return ad_error(ad, adflags);
+ /* retry with O_CREAT */
+ ad->ad_mdp->adf_fd = open(ad_p, oflags, admode);
+ if ( ad->ad_mdp->adf_fd < 0 )
+ return ad_error(ad, adflags);
- ad->ad_mdp->adf_flags = oflags;
- /* just created, set owner if admin owner (root) */
- if (!st_invalid)
- ad_chown(ad_p, &st_dir);
+ ad->ad_mdp->adf_flags = oflags;
+ /* just created, set owner if admin owner (root) */
+ if (!st_invalid)
+ ad_chown(ad_p, &st_dir);
+ break;
+ }
} else {
ad->ad_mdp->adf_flags = nocreatflags;
if (fstat(ad->ad_mdp->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) {
oflags = (flags & ADFLAGS_DIR) | ADFLAGS_HF | ADFLAGS_RDONLY;
- if ((ret = ad_open(adp, name, oflags)) < 0 && errno == EACCES) {
+ if ((ret = ad_open(adp, name, oflags | ADFLAGS_SETSHRMD)) < 0 && errno == EACCES) {
uid = geteuid();
if (seteuid(0)) {
LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));