]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/util/volinfo.c
Merge master
[netatalk.git] / libatalk / util / volinfo.c
index 42712fcf71df4d4a2f9d04c18078eafce2239625..52360b1ece0330089386c5383f9cc619c74403e3 100644 (file)
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-
+#include <unistd.h>
+#include <sys/types.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#ifdef STDC_HEADERS
 #include <string.h>
-#endif
 #include <sys/param.h>
 
 #include <atalk/adouble.h>
@@ -40,6 +36,7 @@
 #include <atalk/logger.h>
 #include <atalk/volinfo.h>
 #include <atalk/volume.h>
+#include <atalk/compat.h>
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB*/
@@ -54,7 +51,6 @@ static const vol_opt_name_t vol_opt_names[] = {
     {AFPVOL_USEDOTS,    "USEDOTS"},     /* use real dots */
     {AFPVOL_LIMITSIZE,  "LIMITSIZE"},   /* limit size for older macs */
     {AFPVOL_MAPASCII,   "MAPASCII"},    /* map the ascii range as well */
-    {AFPVOL_DROPBOX,    "DROPBOX"},     /* dropkludge dropbox support */
     {AFPVOL_NOFILEID,   "NOFILEID"},    /* don't advertise createid resolveid and deleteid calls */
     {AFPVOL_NOSTAT,     "NOSTAT"},      /* advertise the volume even if we can't stat() it
                                          * maybe because it will be mounted later in preexec */
@@ -139,16 +135,32 @@ static char * make_path_absolute(char *path, size_t bufsize)
     char       abspath[MAXPATHLEN];
     char       *p;
 
-    if (stat(path, &st) != 0) {
-        return NULL;
-    }
+    strlcpy(abspath, path, sizeof(abspath));
+
+    /* we might be called from `ad cp ...` with non existing target */
+    if (stat(abspath, &st) != 0) {
+        if (errno != ENOENT)
+            return NULL;
+
+        if (NULL == (p = strrchr(abspath, '/')) )
+            /* single component `ad cp SOURCEFILE TARGETFILE`, use "." instead */
+            strcpy(abspath, ".");
+        else
+            /* try without the last path element */
+            *p = '\0';
 
-    strlcpy (abspath, path, sizeof(abspath));
+        if (stat(abspath, &st) != 0) {
+            return NULL;
+        }
+    }
 
-    if (!S_ISDIR(st.st_mode)) {
-        if (NULL == (p=strrchr(abspath, '/')) )
+    if (S_ISREG(st.st_mode)) {
+        /* single file copy SOURCE */
+        if (NULL == (p = strrchr(abspath, '/')) )
+            /* no path, use "." instead */
             strcpy(abspath, ".");
         else
+            /* try without the last path element */
             *p = '\0';
     }
 
@@ -272,30 +284,25 @@ static int parseline ( char *buf, struct volinfo *vol)
         }
         break;
       case CNIDDBDPORT:
-        vol->v_dbd_port = atoi(value);
-        break;
-      case CNID_DBPATH:
-        if ((vol->v_dbpath = strdup(value)) == NULL) {
+        if ((vol->v_dbd_port = strdup(value)) == NULL) {
            fprintf (stderr, "strdup: %s", strerror(errno));
-            return -1;
+            return -1;            
         }
         break;
+      case CNID_DBPATH:
+          if ((vol->v_dbpath = malloc(MAXPATHLEN+1)) == NULL)
+              return -1;
+          strcpy(vol->v_dbpath, value);
+        break;
       case ADOUBLE_VER:
-        if (strcasecmp(value, "v1") == 0) {
-            vol->v_adouble = AD_VERSION1;
-            vol->ad_path = ad_path;
-        }
-#if AD_VERSION == AD_VERSION2
-        else if (strcasecmp(value, "v2") == 0) {
+        if (strcasecmp(value, "v2") == 0) {
             vol->ad_path = ad_path;
             vol->v_adouble = AD_VERSION2;
-        }
-        else if (strcasecmp(value, "osx") == 0) {
-            vol->v_adouble = AD_VERSION2_OSX;
-            vol->ad_path = ad_path_osx;
-        }
-#endif
-        else  {
+        } else if (strcasecmp(value, "ea") == 0) {
+            vol->ad_path = ad_path_ea;
+            vol->v_adouble = AD_VERSION_EA;
+        } else {
+
            fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
            return -1;
         }
@@ -328,7 +335,7 @@ int loadvolinfo (char *path, struct volinfo *vol)
     char   volinfofile[MAXPATHLEN];
     char   buf[MAXPATHLEN];
     struct flock lock;
-    int    fd;
+    int    fd, len;
     FILE   *fp;
 
     if ( !path || !vol)
@@ -342,9 +349,16 @@ int loadvolinfo (char *path, struct volinfo *vol)
         return -1;
 
     if ((vol->v_path = strdup(volinfofile)) == NULL ) {
-       fprintf (stderr, "strdup: %s", strerror(errno));
+        fprintf (stderr, "strdup: %s", strerror(errno));
         return (-1);
     }
+    /* Remove trailing slashes */
+    len = strlen(vol->v_path);
+    while (len && (vol->v_path[len-1] == '/')) {
+        vol->v_path[len-1] = 0;
+        len--;
+    }
+
     strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
     strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
 
@@ -387,16 +401,70 @@ int loadvolinfo (char *path, struct volinfo *vol)
     if ((vol->v_flags & AFPVOL_INV_DOTS))
         vol->v_ad_options |= ADVOL_INVDOTS;
 
+    vol->retaincount = 1;
+
     fclose(fp);
     return 0;
 }
 
+/*!
+ * Allocate a struct volinfo object for refcounting usage with retain and close, and
+ * call loadvolinfo with it
+ */
+struct volinfo *allocvolinfo(char *path)
+{
+    struct volinfo *p = malloc(sizeof(struct volinfo));
+    if (p == NULL)
+        return NULL;
+
+    if (loadvolinfo(path, p) == -1)
+        return NULL;
+
+    p->malloced = 1;
+
+    return p;
+}
+
+void retainvolinfo(struct volinfo *vol)
+{
+    vol->retaincount++;
+}
+
+/*!
+ * Decrement retain count, free resources when retaincount reaches 0
+ */
+int closevolinfo(struct volinfo *volinfo)
+{
+    if (volinfo->retaincount <= 0)
+        abort();
+
+    volinfo->retaincount--;
+
+    if (volinfo->retaincount == 0) {
+        free(volinfo->v_name); volinfo->v_name = NULL;
+        free(volinfo->v_path); volinfo->v_path = NULL;
+        free(volinfo->v_cnidscheme); volinfo->v_cnidscheme = NULL;
+        free(volinfo->v_dbpath); volinfo->v_dbpath = NULL;
+        free(volinfo->v_volcodepage); volinfo->v_volcodepage = NULL;
+        free(volinfo->v_maccodepage); volinfo->v_maccodepage = NULL;
+        free(volinfo->v_dbd_host); volinfo->v_dbd_host = NULL;
+        free(volinfo->v_dbd_port); volinfo->v_dbd_port = NULL;
+        if (volinfo->malloced) {
+            volinfo->malloced = 0;
+            free(volinfo);
+        }
+    }
+
+    return 0;
+}
+
 /*
  * Save the volume options to a file, used by shell utilities. Writing the file
  * everytime a volume is opened is unnecessary, but it shouldn't hurt much.
  */
 int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_port)
 {
+    uid_t process_uid;
     char buf[16348];
     char item[MAXPATHLEN];
     int fd;
@@ -409,11 +477,31 @@ int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_po
     strlcat (item, "/.AppleDesktop/", sizeof(item));
     strlcat (item, VOLINFOFILE, sizeof(item));
 
-    if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) {
-        LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno));
+    process_uid = geteuid();
+    if (process_uid) {
+        if (seteuid(0) == -1) {
+            process_uid = 0;
+        }
+    }
+
+    if ((fd = open(item, O_RDWR | O_CREAT , 0666)) <0 ) {
+        LOG(log_debug, logtype_default,"Error opening %s: %s", item, strerror(errno));
+        if (process_uid) {
+            if (seteuid(process_uid) == -1) {
+                LOG(log_error, logtype_default, "can't seteuid back %s", strerror(errno));
+                exit(EXITERR_SYS);
+            }
+        }
         return (-1);
     }
 
+    if (process_uid) {
+        if (seteuid(process_uid) == -1) {
+            LOG(log_error, logtype_default, "can't seteuid back %s", strerror(errno));
+            exit(EXITERR_SYS);
+        }
+    }
+
     /* try to get a lock */
     lock.l_start  = 0;
     lock.l_whence = SEEK_SET;
@@ -425,7 +513,7 @@ int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_po
             /* ignore, other process already writing the file */
             return 0;
         } else {
-            LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
+            LOG(log_error, logtype_default, "savevoloptions: cannot get lock: %s", strerror(errno));
             return (-1);
         }
     }
@@ -436,17 +524,11 @@ int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_po
     strlcat(buf, item, sizeof(buf));
 
     switch (vol->v_adouble) {
-        case AD_VERSION1:
-            strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf));
-            break;
         case AD_VERSION2:
             strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf));
             break;
-        case AD_VERSION2_OSX:
-            strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
-            break;
-        case AD_VERSION1_SFM:
-            strlcat(buf, "ADOUBLE_VER:sfm\n", sizeof(buf));
+        case AD_VERSION_EA:
+            strlcat(buf, "ADOUBLE_VER:ea\n", sizeof(buf));
             break;
     }
 
@@ -492,20 +574,28 @@ int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_po
     strlcat(item, "\n", sizeof(item));
     strlcat(buf, item, sizeof(buf));
 
-    /* ExtendedAttrbutes */
+    /* ExtendedAttributes */
     strcpy(item, "EXTATTRTYPE:");
-    if (vol->v_vfs_ea & AFPVOL_EA_AD)
-        strlcat(item, "AFPVOL_EA_AD\n", sizeof(item));
-    else if (vol->v_vfs_ea & AFPVOL_EA_SYS)
+    switch (vol->v_vfs_ea) {
+    case AFPVOL_EA_SYS:
         strlcat(item, "AFPVOL_EA_SYS\n", sizeof(item));
-    else
+        break;
+    case AFPVOL_EA_AD:
+        strlcat(item, "AFPVOL_EA_AD\n", sizeof(item));
+        break;
+    case AFPVOL_EA_NONE:
+        strlcat(item, "AFPVOL_EA_NONE\n", sizeof(item));
+        break;
+    default:
         strlcat(item, "AFPVOL_EA_UNKNOWN\n", sizeof(item));
+    }
+
     strlcat(buf, item, sizeof(buf));
 
     if (strlen(buf) >= sizeof(buf)-1)
-        LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf);
+        LOG(log_debug, logtype_default, "Error writing .volinfo file: buffer too small, %s", buf);
    if (write( fd, buf, strlen(buf)) < 0 || ftruncate(fd, strlen(buf)) < 0 ) {
-       LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
+       LOG(log_debug, logtype_default, "Error writing .volinfo file: %s", strerror(errno));
    }
 
    lock.l_type = F_UNLCK;