]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_open.c
Configurable symlink behaviour
[netatalk.git] / libatalk / adouble / ad_open.c
index 6e9dc85c33eb1f7e74db2c041d6aa17ddc02d416..b2b291b659a2e1d3e7666fa53d5ef5123d490f60 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ad_open.c,v 1.71 2010-03-07 18:27:59 didg Exp $
- *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -283,6 +281,7 @@ static int ad_update(struct adouble *ad, const char *path)
 
     /* last place for failure. */
     if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
+        munmap(buf, st.st_size + shiftdata);
         goto bail_lock;
     }
 
@@ -1014,8 +1013,8 @@ int ad_stat(const char *path, struct stat *stbuf)
     if (!p) {
         return -1;
     }
-//FIXME!
-    return lstat( p, stbuf );
+
+    return stat(p, stbuf);
 }
 
 /* ----------------
@@ -1037,7 +1036,7 @@ static int ad_chown(const char *path, struct stat *stbuf)
     if (default_uid != (uid_t)-1) {
         /* we are root (admin) */
         id = (default_uid)?default_uid:stbuf->st_uid;
-        ret = lchown( path, id, stbuf->st_gid );
+        ret = chown(path, id, stbuf->st_gid);
     }
 #endif
     return ret;
@@ -1080,8 +1079,8 @@ ad_mkdir( const char *path, int mode)
     int st_invalid;
     struct stat stbuf;
 
-    LOG(log_debug, logtype_default, "ad_mkdir: creating ad-directory '%s/%s' with mode %04o",
-        getcwdpath(), path, mode);
+    LOG(log_debug, logtype_default, "ad_mkdir(\"%s\", %04o) {cwd: \"%s\"}",
+        path, mode, getcwdpath());
 
     st_invalid = ad_mode_st(path, &mode, &stbuf);
     ret = mkdir( path, mode );
@@ -1285,33 +1284,28 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
                 }
             }
                 
-            ad->ad_data_fork.adf_fd =open( path, hoflags | O_NOFOLLOW, admode );
+            ad->ad_data_fork.adf_fd = open(path, hoflags | ad_get_syml_opt(ad), admode);
             
-            if (ad->ad_data_fork.adf_fd < 0 ) {
+            if (ad->ad_data_fork.adf_fd == -1) {
                 if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
                     hoflags = oflags;
-                    ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
+                    ad->ad_data_fork.adf_fd = open( path, hoflags | ad_get_syml_opt(ad), admode );
                 }
-                if (ad->ad_data_fork.adf_fd < 0 && errno == ELOOP) {
+                if (ad->ad_data_fork.adf_fd == -1 && errno == OPEN_NOFOLLOW_ERRNO) {
                     int lsz;
 
-                    if (oflags != O_RDONLY)
-                         return -1;
-
-                    ad->ad_data_fork.adf_syml = malloc(PATH_MAX+1);
-                    lsz = readlink(path, ad->ad_data_fork.adf_syml, PATH_MAX);
+                    ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
+                    lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN);
                     if (lsz <= 0) {
                         free(ad->ad_data_fork.adf_syml);
                         return -1;
                     }
-                    ad->ad_data_fork.adf_syml[lsz]=0;
-                    ad->ad_data_fork.adf_syml = realloc(ad->ad_data_fork.adf_syml,lsz+1);
-                    // XX
-                    ad->ad_data_fork.adf_fd = 0;
+                    ad->ad_data_fork.adf_syml[lsz] = 0;
+                    ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
                 }
             }
 
-            if ( ad->ad_data_fork.adf_fd < 0)
+            if ( ad->ad_data_fork.adf_fd == -1 )
                 return -1;
 
             AD_SET(ad->ad_data_fork.adf_off);
@@ -1372,11 +1366,11 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
     if (!(adflags & ADFLAGS_RDONLY)) {
         hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
     }
-    ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+    ad->ad_md->adf_fd = open(ad_p, hoflags | ad_get_syml_opt(ad), 0);
     if (ad->ad_md->adf_fd < 0 ) {
         if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
             hoflags = oflags & ~(O_CREAT | O_EXCL);
-            ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+            ad->ad_md->adf_fd = open(ad_p, hoflags | ad_get_syml_opt(ad), 0);
         }
     }
 
@@ -1387,7 +1381,8 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
              * here.
              * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
              */
-            LOG(log_debug, logtype_default, "ad_open: creating new adouble file: %s/%s", getcwdpath(), ad_p);
+            LOG(log_debug, logtype_default, "ad_open(\"%s\"): {cwd: \"%s\"} creating adouble file",
+                ad_p, getcwdpath());
             admode = mode;
             errno = 0;
             st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
@@ -1396,7 +1391,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
             }
             admode = ad_hf_mode(admode);
             if ((errno == ENOENT) && (ad->ad_flags != AD_VERSION2_OSX)) {
-                if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
+                if (ad->ad_ops->ad_mkrf(ad_p) < 0) {
                     return ad_error(ad, adflags);
                 }
                 admode = mode;
@@ -1586,6 +1581,41 @@ int ad_metadata(const char *name, int flags, struct adouble *adp)
     return ret;
 }
 
+/*
+ * @brief openat like wrapper for ad_metadata
+ */
+int ad_metadataat(int dirfd, const char *name, int flags, struct adouble *adp)
+{
+    int ret = 0;
+    int cwdfd = -1;
+
+    if (dirfd != -1) {
+        if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    if (ad_metadata(name, flags, adp) < 0) {
+        ret = -1;
+        goto exit;
+    }
+
+    if (dirfd != -1) {
+        if (fchdir(cwdfd) != 0) {
+            LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting");
+            exit(EXITERR_SYS);
+        }
+    }
+
+exit:
+    if (cwdfd != -1)
+        close(cwdfd);
+
+    return ret;
+
+}
+
 /* ----------------------------------- */
 static int new_rfork(const char *path, struct adouble *ad, int adflags)
 {
@@ -1643,7 +1673,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
         memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
     }
 
-    if (lstat(path, &st) < 0) {
+    if (ostat(path, &st, ad_get_syml_opt(ad)) < 0) {
         return -1;
     }
 
@@ -1665,3 +1695,39 @@ int ad_refresh(struct adouble *ad)
 
     return ad->ad_ops->ad_header_read(ad, NULL);
 }
+
+int ad_openat(int dirfd,  /* dir fd openat like */
+              const char *path,
+              int adflags,
+              int oflags,
+              int mode,
+              struct adouble  *ad)
+{
+    int ret = 0;
+    int cwdfd = -1;
+
+    if (dirfd != -1) {
+        if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    if (ad_open(path, adflags, oflags, mode, ad) < 0) {
+        ret = -1;
+        goto exit;
+    }
+
+    if (dirfd != -1) {
+        if (fchdir(cwdfd) != 0) {
+            LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting");
+            exit(EXITERR_SYS);
+        }
+    }
+
+exit:
+    if (cwdfd != -1)
+        close(cwdfd);
+
+    return ret;
+}