]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/ofork.c
Spotlight: use async Tracker SPARQL API
[netatalk.git] / etc / afpd / ofork.c
index fc91c03b18fa51f44f48be121d1672a2e6f5ab84..59e9f153041d4da0768055a9f548ada9dd594171 100644 (file)
 #include <atalk/bstradd.h>
 #include <atalk/globals.h>
 #include <atalk/fce_api.h>
+#include <atalk/ea.h>
 
 #include "volume.h"
 #include "directory.h"
 #include "fork.h"
+#include "desktop.h"
 
 /* we need to have a hashed list of oforks (by dev inode) */
 #define OFORK_HASHSIZE  64
@@ -228,14 +230,14 @@ struct ofork *of_find(const uint16_t ofrefnum )
 }
 
 /* -------------------------- */
-int of_stat(struct path *path)
+int of_stat(const struct vol *vol, struct path *path)
 {
     int ret;
 
     path->st_errno = 0;
     path->st_valid = 1;
 
-    if ((ret = lstat(path->u_name, &path->st)) < 0) {
+    if ((ret = ostat(path->u_name, &path->st, vol_syml_opt(vol))) < 0) {
         LOG(log_debug, logtype_afpd, "of_stat('%s/%s': %s)",
             cfrombstr(curdir->d_fullpath), path->u_name, strerror(errno));
        path->st_errno = errno;
@@ -274,7 +276,7 @@ int of_statdir(struct vol *vol, struct path *path)
 
     if (*path->m_name) {
         /* not curdir */
-        return of_stat (path);
+        return of_stat(vol, path);
     }
     path->st_errno = 0;
     path->st_valid = 1;
@@ -286,7 +288,7 @@ int of_statdir(struct vol *vol, struct path *path)
 
     LOG(log_debug, logtype_afpd, "of_statdir: stating: '%s'", pathname);
 
-    if (!(ret = lstat(pathname, &path->st)))
+    if (!(ret = ostat(pathname, &path->st, vol_syml_opt(vol))))
         return 0;
 
     path->st_errno = errno;
@@ -297,7 +299,7 @@ int of_statdir(struct vol *vol, struct path *path)
            return -1;
        path->st_errno = 0;
 
-       if ((ret = lstat(cfrombstr(path->d_dir->d_u_name), &path->st)) < 0) 
+       if ((ret = ostat(cfrombstr(path->d_dir->d_u_name), &path->st, vol_syml_opt(vol))) < 0) 
            path->st_errno = errno;
     }
 
@@ -305,13 +307,13 @@ int of_statdir(struct vol *vol, struct path *path)
 }
 
 /* -------------------------- */
-struct ofork *of_findname(struct path *path)
+struct ofork *of_findname(const struct vol *vol, struct path *path)
 {
     struct ofork *of;
     struct file_key key;
 
     if (!path->st_valid) {
-        of_stat(path);
+        of_stat(vol, path);
     }
 
     if (path->st_errno)
@@ -364,7 +366,7 @@ struct ofork *of_findnameat(int dirfd, struct path *path)
 }
 #endif
 
-void of_dealloc( struct ofork *of)
+void of_dealloc(struct ofork *of)
 {
     if (!oforks)
         return;
@@ -378,19 +380,19 @@ void of_dealloc( struct ofork *of)
     if ( of->of_ad->ad_refcount <= 0) {
         free( of->of_ad->ad_name );
         free( of->of_ad);
-    } else {/* someone's still using it. just free this user's locks */
-        ad_unlock(of->of_ad, of->of_refnum, of->of_flags & AFPFORK_ERROR ? 0 : 1);
     }
 
     free( of );
 }
 
 /* --------------------------- */
-int of_closefork(struct ofork *ofork)
+int of_closefork(const AFPObj *obj, struct ofork *ofork)
 {
     struct timeval      tv;
     int         adflags = 0;
     int                 ret;
+    struct dir *dir;
+    bstring forkpath = NULL;
 
     adflags = 0;
     if (ofork->of_flags & AFPFORK_DATA)
@@ -407,17 +409,74 @@ int of_closefork(struct ofork *ofork)
         }
     }
 
+    dir = dirlookup(ofork->of_vol, ofork->of_did);
+    if (dir == NULL) {
+        LOG(log_debug, logtype_afpd, "dirlookup failed for %ju", (uintmax_t)ofork->of_did);
+    }
+
+    if (dir) {
+        forkpath = bformat("%s/%s", bdata(dir->d_fullpath), of_name(ofork));
+    }
+
     /* Somone has used write_fork, we assume file was changed, register it to file change event api */
-    if (ofork->of_flags & AFPFORK_MODIFIED) {
-        fce_register_file_modification(ofork);
+    if ((ofork->of_flags & AFPFORK_MODIFIED) && (forkpath)) {
+        fce_register(obj, FCE_FILE_MODIFY, bdata(forkpath), NULL);
     }
 
+    ad_unlock(ofork->of_ad, ofork->of_refnum, ofork->of_flags & AFPFORK_ERROR ? 0 : 1);
+
+#ifdef HAVE_FSHARE_T
+    if (obj->options.flags & OPTION_SHARE_RESERV) {
+        fshare_t shmd;
+        shmd.f_id = ofork->of_refnum;
+        if (AD_DATA_OPEN(ofork->of_ad))
+            fcntl(ad_data_fileno(ofork->of_ad), F_UNSHARE, &shmd);
+        if (AD_RSRC_OPEN(ofork->of_ad))
+            fcntl(ad_reso_fileno(ofork->of_ad), F_UNSHARE, &shmd);
+    }
+#endif
+
     ret = 0;
+
+    /*
+     * Check for 0 byte size resource forks, delete them.
+     * Here's the deal:
+     * (1) the size must be 0
+     * (2) the fork must refer to a resource fork
+     * (3) the refcount must be 1 which means this fork has the last
+     *     reference to the adouble struct and the subsequent
+     *     ad_close() will close the assoiciated fd.
+     * (4) nobody else has the resource fork open
+     *
+     * We only do this for ._ AppleDouble resource forks, not for
+     * xattr resource forks, because the test-suite then fails several
+     * tests on Solaris, the reason for that still needs to be
+     * determined.
+     */
+    if ((ofork->of_ad->ad_rlen == 0)
+        && (ofork->of_flags & AFPFORK_RSRC)
+        && (ofork->of_ad->ad_rfp->adf_refcount == 1)
+        && (ad_openforks(ofork->of_ad, ATTRBIT_DOPEN) == 0)) {
+
+#ifndef HAVE_EAFD
+        (void)unlink(ofork->of_ad->ad_ops->ad_path(
+                         mtoupath(ofork->of_vol,
+                                  of_name(ofork),
+                                  ofork->of_did,
+                                  utf8_encoding(obj)),
+                         0));
+#endif
+    }
+
     if ( ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD) < 0 ) {
         ret = -1;
     }
 
-    of_dealloc( ofork );
+    of_dealloc(ofork);
+
+    if (forkpath)
+        bdestroy(forkpath);
+
     return ret;
 }
 
@@ -429,7 +488,7 @@ struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *
     struct ofork        *of;
     struct adouble      *adp;
 
-    if ((of = of_findname(path))) {
+    if ((of = of_findname(vol, path))) {
         adp = of->of_ad;
     } else {
         ad_init(ad, vol);
@@ -441,7 +500,7 @@ struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *
 /* ----------------------
    close all forks for a volume
 */
-void of_closevol(const struct vol *vol)
+void of_closevol(const AFPObj *obj, const struct vol *vol)
 {
     int refnum;
 
@@ -450,7 +509,7 @@ void of_closevol(const struct vol *vol)
 
     for ( refnum = 0; refnum < nforks; refnum++ ) {
         if (oforks[ refnum ] != NULL && oforks[refnum]->of_vol == vol) {
-            if (of_closefork( oforks[ refnum ]) < 0 ) {
+            if (of_closefork(obj, oforks[ refnum ]) < 0 ) {
                 LOG(log_error, logtype_afpd, "of_closevol: %s", strerror(errno) );
             }
         }
@@ -461,7 +520,7 @@ void of_closevol(const struct vol *vol)
 /* ----------------------
    close all forks for a volume
 */
-void of_close_all_forks(void)
+void of_close_all_forks(const AFPObj *obj)
 {
     int refnum;
 
@@ -470,7 +529,7 @@ void of_close_all_forks(void)
 
     for ( refnum = 0; refnum < nforks; refnum++ ) {
         if (oforks[ refnum ] != NULL) {
-            if (of_closefork( oforks[ refnum ]) < 0 ) {
+            if (of_closefork(obj, oforks[ refnum ]) < 0 ) {
                 LOG(log_error, logtype_afpd, "of_close_all_forks: %s", strerror(errno) );
             }
         }