+ /* either there's a lock or we already know one fork is open */
+
+ if (!(attrbits & ATTRBIT_DOPEN)) {
+ off = AD_FILELOCK_OPEN_WR;
+ ret = testlock(&ad->ad_data_fork, off, 2) > 0 ? ATTRBIT_DOPEN : 0;
+ }
+
+ if (!(attrbits & ATTRBIT_ROPEN)) {
+ off = AD_FILELOCK_RSRC_OPEN_WR;
+ ret |= testlock(&ad->ad_data_fork, off, 2) > 0? ATTRBIT_ROPEN : 0;
+ }
+
+ return ret;
+}
+
+static int ad_testlock_v2(struct adouble *ad, int eid, const off_t off)
+{
+ struct ad_fd *adf;
+ off_t lock_offset;
+
+ lock_offset = off;
+ if (eid == ADEID_DFORK) {
+ adf = &ad->ad_data_fork;
+ if (ad_meta_fileno(ad) != -1) {
+ adf = ad->ad_mdp;
+ lock_offset = df2off(off);
+ }
+ } else { /* rfork */
+ if (ad_meta_fileno(ad) == -1) {
+ /* there's no resource fork. return no lock */
+ return 0;
+ }
+ adf = ad->ad_mdp;
+ lock_offset = hf2off(off);
+ }
+ return testlock(adf, lock_offset, 1);
+}
+
+static int ad_testlock_ea(struct adouble *ad, int eid, const off_t off)
+{
+ off_t lock_offset;
+
+ if (eid == ADEID_DFORK) {
+ lock_offset = off;
+ } else { /* rfork */
+ lock_offset = rf2off(off);
+ }
+ return testlock(&ad->ad_data_fork, lock_offset, 1);
+}
+
+#define LTYPE2STRBUFSIZ 128
+static const char *locktypetostr(int type)
+{
+ int first = 1;
+ static char buf[LTYPE2STRBUFSIZ];
+
+ buf[0] = 0;
+
+ if (type == 0) {
+ strlcat(buf, "CLR", LTYPE2STRBUFSIZ);
+ first = 0;
+ return buf;
+ }
+ if (type & ADLOCK_RD) {
+ if (!first)
+ strlcat(buf, "|", LTYPE2STRBUFSIZ);
+ strlcat(buf, "RD", LTYPE2STRBUFSIZ);
+ first = 0;
+ }
+ if (type & ADLOCK_WR) {
+ if (!first)
+ strlcat(buf, "|", LTYPE2STRBUFSIZ);
+ strlcat(buf, "WR", LTYPE2STRBUFSIZ);
+ first = 0;
+ }
+ if (type & ADLOCK_UPGRADE) {
+ if (!first)
+ strlcat(buf, "|", LTYPE2STRBUFSIZ);
+ strlcat(buf, "UPG", LTYPE2STRBUFSIZ);
+ first = 0;
+ }
+ if (type & ADLOCK_FILELOCK) {
+ if (!first)
+ strlcat(buf, "|", LTYPE2STRBUFSIZ);
+ strlcat(buf, "FILELOCK", LTYPE2STRBUFSIZ);
+ first = 0;
+ }
+
+ return buf;
+}
+
+/******************************************************************************
+ * Public functions
+ ******************************************************************************/
+
+int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len, int fork)
+{
+ struct flock lock;
+ struct ad_fd *adf;
+ adf_lock_t *adflock;
+ int oldlock;
+ int i;
+ int type;
+
+ LOG(log_debug, logtype_default, "ad_lock(\"%s\", %s, %s, off: %jd, len: %jd): BEGIN",
+ ad->ad_m_name ? ad->ad_m_name : "???",
+ eid == ADEID_DFORK ? "data" : "reso",
+ locktypetostr(locktype), (intmax_t)off, (intmax_t)len);
+
+ if ((locktype & ADLOCK_FILELOCK) && (len != 1))
+ /* safety check */
+ return -1;
+
+ lock.l_start = off;
+ type = locktype;
+
+ if (eid == ADEID_DFORK) {
+ adf = &ad->ad_data_fork;
+ if ((ad->ad_vers == AD_VERSION2) && (type & ADLOCK_FILELOCK)) {
+ if (ad_meta_fileno(ad) != -1) { /* META */
+ adf = ad->ad_mdp;
+ lock.l_start = df2off(off);
+ }
+ }
+ } else { /* rfork */
+ switch (ad->ad_vers) {
+ case AD_VERSION2:
+ if (ad_meta_fileno(ad) == -1 || ad_reso_fileno(ad) == -1) {
+ /* there's no meta data. return a lock error
+ * otherwise if a second process is able to create it
+ * locks are a mess. */
+ errno = EACCES;
+ return -1;
+ }
+ if (type & ADLOCK_FILELOCK) {
+ adf = ad->ad_mdp; /* either resource or meta data (set in ad_open) */
+ lock.l_start = hf2off(off);
+ } else {
+ /* we really want the resource fork it's a byte lock */
+ adf = &ad->ad_resource_fork;
+ lock.l_start += ad_getentryoff(ad, eid);
+ }
+ break;
+
+ case AD_VERSION_EA:
+ if (type & ADLOCK_FILELOCK) {
+ adf = &ad->ad_data_fork;
+ lock.l_start = rf2off(off);
+ } else {
+ adf = ad->ad_rfp;
+#if HAVE_EAFD
+ lock.l_start = off;
+#else
+ lock.l_start= ADEDOFF_RFORK_OSX + off;
+#endif
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ /* NOTE: we can't write lock a read-only file. on those, we just
+ * make sure that we have a read lock set. that way, we at least prevent
+ * someone else from really setting a deny read/write on the file.
+ */
+ if (!(adf->adf_flags & O_RDWR) && (type & ADLOCK_WR)) {
+ type = (type & ~ADLOCK_WR) | ADLOCK_RD;
+ }