]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/util/volinfo.c
Add all EA opts to volinfo
[netatalk.git] / libatalk / util / volinfo.c
index 2b0496044da9205ad7f4e664984443c816245c4f..ef438c5d278f5b103a968e8e41953c9cad4d5021 100644 (file)
 #include <atalk/util.h>
 #include <atalk/logger.h>
 #include <atalk/volinfo.h>
+#include <atalk/volume.h>
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB*/
 
+static const vol_opt_name_t vol_opt_names[] = {
+    {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
+    {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
+    {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
+    {AFPVOL_RO,         "READONLY"},    /* read-only volume */
+    {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
+    {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
+    {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 */
+    {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
+    {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
+    {AFPVOL_CASEINSEN,  "CASEINSENSITIVE"}, /* volume is case insensitive */
+    {AFPVOL_EILSEQ,     "ILLEGALSEQ"},  /* encode illegal sequence */
+    {AFPVOL_CACHE,      "CACHEID"},     /* Use adouble v2 CNID caching, default don't use it */
+    {AFPVOL_INV_DOTS,   "INVISIBLEDOTS"}, 
+    {AFPVOL_ACLS,       "ACLS"},        /* Vol supports ACLs */
+    {AFPVOL_TM,         "TM"},          /* Set "kSupportsTMLockSteal" is volume attributes */
+    {0, NULL}
+};
+
+static const vol_opt_name_t vol_opt_casefold[] = {
+    {AFPVOL_MTOUUPPER,  "MTOULOWER"},
+    {AFPVOL_MTOULOWER,  "MTOULOWER"},
+    {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
+    {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
+    {0, NULL}
+};
+
+typedef struct {
+    const char *name;
+    int type;
+} info_option_t;
+
 #define MAC_CHARSET 0
 #define VOL_CHARSET 1
 #define ADOUBLE_VER 2
 #define CNID_DBPATH 6
 #define VOLUME_OPTS 7
 #define VOLCASEFOLD 8
+#define EXTATTRTYPE 9
 
-typedef struct _info_option {
-    const char *name;
-    int type;
-} _info_option;
-
-static const _info_option info_options[] = {
+static const info_option_t info_options[] = {
     {"MAC_CHARSET", MAC_CHARSET},
     {"VOL_CHARSET", VOL_CHARSET},
     {"ADOUBLE_VER", ADOUBLE_VER},
@@ -68,39 +103,8 @@ static const _info_option info_options[] = {
     {"CNID_DBPATH", CNID_DBPATH},
     {"VOLUME_OPTS", VOLUME_OPTS},
     {"VOLCASEFOLD", VOLCASEFOLD},
-    {NULL, 0}
-};
-
-typedef struct _vol_opt_name {
-    const u_int32_t option;
-    const char      *name;
-} _vol_opt_name;
-
-static const _vol_opt_name vol_opt_names[] = {
-    {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
-    {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
-    {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
-    {AFPVOL_RO,         "READONLY"},    /* read-only volume */
-    {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
-    {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
-    {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 */
-    {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
-    {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
-    {0, NULL}
-};
-
-static const _vol_opt_name vol_opt_casefold[] = {
-    {AFPVOL_MTOUUPPER,  "MTOULOWER"},
-    {AFPVOL_MTOULOWER,  "MTOULOWER"},
-    {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
-    {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
-    {0, NULL}
+    {"EXTATTRTYPE", EXTATTRTYPE},
+   {NULL, 0}
 };
 
 static char* find_in_path( char *path, char *subdir, size_t maxlen)
@@ -112,9 +116,6 @@ static char* find_in_path( char *path, char *subdir, size_t maxlen)
     pos = strrchr(path, '/');
 
     while ( stat(path, &st) != 0) {
-#ifdef DEBUG
-        fprintf(stderr, "searching in path %s\n", path);
-#endif
         path[pos-path]=0;
         if ((pos = strrchr(path, '/'))) {
             path[pos-path]=0;
@@ -127,9 +128,7 @@ static char* find_in_path( char *path, char *subdir, size_t maxlen)
 
     path[pos-path] = '/';
     path[pos-path+1] = 0;
-#ifdef DEBUG
-    fprintf(stderr, "%s path %s\n", subdir, path);
-#endif
+
     return path;
 }
 
@@ -148,22 +147,21 @@ static char * make_path_absolute(char *path, size_t bufsize)
 
     if (!S_ISDIR(st.st_mode)) {
         if (NULL == (p=strrchr(abspath, '/')) )
-            return NULL;
-        *p = '\0';
+            strcpy(abspath, ".");
+        else
+            *p = '\0';
     }
 
-    getcwd(savecwd, sizeof(savecwd));
-    if ((chdir(abspath)) < 0)  
+    if (!getcwd(savecwd, sizeof(savecwd)) || chdir(abspath) < 0)       
         return NULL;
 
-    getcwd(abspath, sizeof(abspath));
-    chdir (savecwd);
-
+    if (!getcwd(abspath, sizeof(abspath)) || chdir (savecwd) < 0)
+        return NULL;
+    
     if (strlen(abspath) > bufsize)
         return NULL;
 
     strlcpy(path, abspath, bufsize);
-
     return path;
 }
 
@@ -195,10 +193,10 @@ int vol_load_charsets( struct volinfo *vol)
     return 0;
 }
 
-static int parse_options (char *buf, int *flags, const _vol_opt_name* options)
+static int parse_options (char *buf, int *flags, const vol_opt_name_t *options)
 {
     char *p, *q;
-    const _vol_opt_name *op;
+    const vol_opt_name_t *op;
 
     q = p = buf; 
 
@@ -227,7 +225,7 @@ static int parseline ( char *buf, struct volinfo *vol)
     char *value;
     size_t len;
     int  option=-1;
-    const _info_option  *p  = &info_options[0];
+    const info_option_t  *p  = &info_options[0];
 
     if (NULL == ( value = strchr(buf, ':')) )
        return 1;
@@ -251,25 +249,25 @@ static int parseline ( char *buf, struct volinfo *vol)
     switch (option) {
       case MAC_CHARSET:
         if ((vol->v_maccodepage = strdup(value)) == NULL) {
-           fprintf (stderr, "strdup: %m");
+           fprintf (stderr, "strdup: %s", strerror(errno));
             return -1;
         }
         break;
       case VOL_CHARSET:
         if ((vol->v_volcodepage = strdup(value)) == NULL) {
-           fprintf (stderr, "strdup: %m");
+           fprintf (stderr, "strdup: %s", strerror(errno));
             return -1;
         }
         break;
       case CNIDBACKEND:
         if ((vol->v_cnidscheme = strdup(value)) == NULL) {
-           fprintf (stderr, "strdup: %m");
+           fprintf (stderr, "strdup: %s", strerror(errno));
             return -1;
         }
         break;
       case CNIDDBDHOST:
         if ((vol->v_dbd_host = strdup(value)) == NULL) {
-           fprintf (stderr, "strdup: %m");
+           fprintf (stderr, "strdup: %s", strerror(errno));
             return -1;
         }
         break;
@@ -278,7 +276,7 @@ static int parseline ( char *buf, struct volinfo *vol)
         break;
       case CNID_DBPATH:
         if ((vol->v_dbpath = strdup(value)) == NULL) {
-           fprintf (stderr, "strdup: %m");
+           fprintf (stderr, "strdup: %s", strerror(errno));
             return -1;
         }
         break;
@@ -308,14 +306,17 @@ static int parseline ( char *buf, struct volinfo *vol)
       case VOLCASEFOLD:
         parse_options(value, &vol->v_casefold, &vol_opt_casefold[0]);
         break;
+    case EXTATTRTYPE:
+        if (strcasecmp(value, "AFPVOL_EA_AD") == 0)    
+            vol->v_vfs_ea = AFPVOL_EA_AD;
+        else if (strcasecmp(value, "AFPVOL_EA_SYS") == 0)
+            vol->v_vfs_ea = AFPVOL_EA_SYS;
+        break;
       default:
        fprintf (stderr, "unknown volume information: %s, %s", buf, value);
        return (-1);
         break;
     }
-#ifdef DEBUG
-    printf ("volume information: %s, %s", buf, value);
-#endif
         
     return 0;
 }
@@ -341,7 +342,7 @@ int loadvolinfo (char *path, struct volinfo *vol)
         return -1;
 
     if ((vol->v_path = strdup(volinfofile)) == NULL ) {
-       fprintf (stderr, "strdup: %m");
+       fprintf (stderr, "strdup: %s", strerror(errno));
         return (-1);
     }
     strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
@@ -349,7 +350,7 @@ int loadvolinfo (char *path, struct volinfo *vol)
 
     /* open the file read only */
     if ( NULL == (fp = fopen( volinfofile, "r")) )  {
-       fprintf (stderr, "error opening volinfo (%s): %m", volinfofile);
+       fprintf (stderr, "error opening volinfo (%s): %s", volinfofile, strerror(errno));
         return (-1);
     }
     fd = fileno(fp); 
@@ -375,6 +376,148 @@ int loadvolinfo (char *path, struct volinfo *vol)
     lock.l_type = F_UNLCK;
     fcntl(fd, F_SETLK, &lock);
 
+    /* Translate vol options to ad options like afp/volume.c does it */
+    vol->v_ad_options = 0;
+    if ((vol->v_flags & AFPVOL_NODEV))
+        vol->v_ad_options |= ADVOL_NODEV;
+    if ((vol->v_flags & AFPVOL_CACHE))
+        vol->v_ad_options |= ADVOL_CACHE;
+    if ((vol->v_flags & AFPVOL_UNIX_PRIV))
+        vol->v_ad_options |= ADVOL_UNIXPRIV;
+    if ((vol->v_flags & AFPVOL_INV_DOTS))
+        vol->v_ad_options |= ADVOL_INVDOTS;
+
     fclose(fp);
     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)
+{
+    char buf[16348];
+    char item[MAXPATHLEN];
+    int fd;
+    int ret = 0;
+    struct flock lock;
+    const vol_opt_name_t *op = &vol_opt_names[0];
+    const vol_opt_name_t *cf = &vol_opt_casefold[0];
+
+    strlcpy (item, vol->v_path, sizeof(item));
+    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));
+        return (-1);
+    }
+
+    /* try to get a lock */
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type   = F_WRLCK;
+
+    if (fcntl(fd, F_SETLK, &lock) < 0) {
+        if (errno == EACCES || errno == EAGAIN) {
+            /* ignore, other process already writing the file */
+            return 0;
+        } else {
+            LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
+            return (-1);
+        }
+    }
+
+    /* write volume options */
+    snprintf(buf, sizeof(buf), "MAC_CHARSET:%s\n", vol->v_maccodepage);
+    snprintf(item, sizeof(item), "VOL_CHARSET:%s\n", vol->v_volcodepage);
+    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));
+            break;
+    }
+
+    strlcat(buf, "CNIDBACKEND:", sizeof(buf));
+    strlcat(buf, vol->v_cnidscheme, sizeof(buf));
+    strlcat(buf, "\n", sizeof(buf));
+
+    strlcat(buf, "CNIDDBDHOST:", sizeof(buf));
+    strlcat(buf, Cnid_srv, sizeof(buf));
+    strlcat(buf, "\n", sizeof(buf));
+
+    strlcat(buf, "CNIDDBDPORT:", sizeof(buf));
+    strlcat(buf, Cnid_port, sizeof(buf));
+    strlcat(buf, "\n", sizeof(buf));
+
+    strcpy(item, "CNID_DBPATH:");
+    if (vol->v_dbpath)
+        strlcat(item, vol->v_dbpath, sizeof(item));
+    else
+        strlcat(item, vol->v_path, sizeof(item));
+    strlcat(item, "\n", sizeof(item));
+    strlcat(buf, item, sizeof(buf));
+
+    /* volume flags */
+    strcpy(item, "VOLUME_OPTS:");
+    for (;op->name; op++) {
+       if ( (vol->v_flags & op->option) ) {
+            strlcat(item, op->name, sizeof(item));
+            strlcat(item, " ", sizeof(item));
+        }
+    }
+    strlcat(item, "\n", sizeof(item));
+    strlcat(buf, item, sizeof(buf));
+
+    /* casefold flags */
+    strcpy(item, "VOLCASEFOLD:");
+    for (;cf->name; cf++) {
+        if ( (vol->v_casefold & cf->option) ) {
+            strlcat(item, cf->name, sizeof(item));
+            strlcat(item, " ", sizeof(item));
+        }
+    }
+    strlcat(item, "\n", sizeof(item));
+    strlcat(buf, item, sizeof(buf));
+
+    /* ExtendedAttributes */
+    strcpy(item, "EXTATTRTYPE:");
+    switch (vol->v_vfs_ea) {
+    case AFPVOL_EA_SYS:
+        strlcat(item, "AFPVOL_EA_SYS\n", sizeof(item));
+        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);
+   if (write( fd, buf, strlen(buf)) < 0 || ftruncate(fd, strlen(buf)) < 0 ) {
+       LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
+   }
+
+   lock.l_type = F_UNLCK;
+   fcntl(fd, F_SETLK, &lock);
+   close (fd);
+   return ret;
+}