]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/volume.c
fix a bug in default CREATOR/TYPE handling.
[netatalk.git] / etc / afpd / volume.c
index 75e72d4bba40afbc735cde98da91f2cf2347e0e8..068142359c3aa6834d812b0ee7dc2a13db7062f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.c,v 1.51.2.7.2.27 2004-03-20 00:48:28 bfernhomberg Exp $
+ * $Id: volume.c,v 1.51.2.7.2.33.2.1 2004-10-20 20:05:27 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -141,13 +141,47 @@ typedef struct _special_folder {
 static const _special_folder special_folders[] = {
   {"Network Trash Folder",     1,  0777,  1},
   {"Temporary Items",          1,  0777,  1},
+  {".AppleDesktop",            1,  0777,  0},
 #if 0
   {"TheFindByContentFolder",   0,     0,  1},
   {"TheVolumeSettingsFolder",  0,     0,  1},
 #endif
   {NULL, 0, 0, 0}};
 
+typedef struct _volopt_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}
+};
+
 static void handle_special_folders (const struct vol *);
+static int savevoloptions (const struct vol *);
 
 static __inline__ void volfree(struct vol_option *options,
                                const struct vol_option *save)
@@ -367,7 +401,7 @@ static void volset(struct vol_option *options, struct vol_option *save,
     } else if (optionok(tmp, "codepage:", val)) {
        LOG (log_error, logtype_afpd, "The old codepage system has been removed. Please make sure to read the documentation !!!!");
        /* Make sure we don't screw anything */
-       exit (-1);
+       exit (EXITERR_CONF);
     } else if (optionok(tmp, "volcharset:", val)) {
         setoption(options, save, VOLOPT_ENCODING, val);
     } else if (optionok(tmp, "maccharset:", val)) {
@@ -619,7 +653,6 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
            volume->v_adouble = options[VOLOPT_ADOUBLE].i_value;
        else 
            volume->v_adouble = AD_VERSION;
-       initvoladouble(volume);
 #ifdef FORCE_UIDGID
         if (options[VOLOPT_FORCEUID].c_value) {
             volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
@@ -650,6 +683,7 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
         }
     }
 
+    initvoladouble(volume);
     volume->v_next = Volumes;
     Volumes = volume;
     return 0;
@@ -804,7 +838,12 @@ static void sortextmap( void)
     }
     if (Extmap_cnt) {
         qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp);
-        Defextmap = Extmap;
+        if (*Extmap->em_ext == 0) {
+            /* the first line is really "." the default entry, 
+             * we remove the leading '.' in setextmap
+            */
+            Defextmap = Extmap;
+        }
     }
 }
 
@@ -1460,7 +1499,8 @@ int       ibuflen, *rbuflen;
     struct vol         *volume;
     char       *data;
     char               *namebuf;
-    int                        vcnt, len;
+    int                        vcnt;
+    size_t             len;
 
     load_volumes(obj);
 
@@ -1468,7 +1508,7 @@ int       ibuflen, *rbuflen;
     for ( vcnt = 0, volume = Volumes; volume; volume = volume->v_next ) {
         if (!(volume->v_flags & AFPVOL_NOSTAT)) {
             if ( stat( volume->v_path, &st ) < 0 ) {
-                LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s",
+                LOG(log_info, logtype_afpd, "afp_getsrvrparms(%s): stat: %s",
                         volume->v_path, strerror(errno) );
                 continue;              /* can't access directory */
             }
@@ -1479,6 +1519,11 @@ int      ibuflen, *rbuflen;
         if (volume->v_hide) {
             continue;          /* config file changed but the volume was mounted */
         }
+       len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset),
+                                       &namebuf, volume->v_name);
+       if (len == (size_t)-1)
+               continue;
+
         /* set password bit if there's a volume password */
         *data = (volume->v_password) ? AFPSRVR_PASSWD : 0;
 
@@ -1490,11 +1535,6 @@ int      ibuflen, *rbuflen;
            off.. <shirsch@ibm.net> */
         *data |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0;
         *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */
-
-       len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset),
-                                       &namebuf, volume->v_name);
-       if (len <= 0)
-               continue;
         *data++ = len;
         memcpy(data, namebuf, len );
         data += len;
@@ -1505,7 +1545,7 @@ int       ibuflen, *rbuflen;
     *rbuflen = data - rbuf;
     data = rbuf;
     if ( gettimeofday( &tv, 0 ) < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_getsrvrparms(%s): gettimeofday: %s", volume->v_path, strerror(errno) );
         *rbuflen = 0;
         return AFPERR_PARAM;
     }
@@ -1602,7 +1642,7 @@ int               ibuflen, *rbuflen;
 
     if (volume->v_root_preexec) {
        if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) {
-            LOG(log_error, logtype_afpd, "afp_openvol: root preexec : %d", ret );
+            LOG(log_error, logtype_afpd, "afp_openvol(%s): root preexec : %d", volume->v_path, ret );
             ret = AFPERR_MISC;
             goto openvol_err;
        }
@@ -1614,7 +1654,7 @@ int               ibuflen, *rbuflen;
 
     if (volume->v_preexec) {
        if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) {
-            LOG(log_error, logtype_afpd, "afp_openvol: preexec : %d", ret );
+            LOG(log_error, logtype_afpd, "afp_openvol(%s): preexec : %d", volume->v_path, ret );
             ret = AFPERR_MISC;
             goto openvol_err;
        }
@@ -1639,7 +1679,7 @@ int               ibuflen, *rbuflen;
     
     if ( NULL == getcwd(path, MAXPATHLEN)) {
         /* shouldn't be fatal but it will fail later */
-        LOG(log_error, logtype_afpd, "afp_openvol: volume pathlen too long" );
+        LOG(log_error, logtype_afpd, "afp_openvol(%s): volume pathlen too long", volume->v_path);
         ret = AFPERR_MISC;
         goto openvol_err;
     }        
@@ -1651,7 +1691,7 @@ int               ibuflen, *rbuflen;
        
     if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) {
        free(vol_mname);
-        LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
         ret = AFPERR_MISC;
         goto openvol_err;
     }
@@ -1711,7 +1751,10 @@ int              ibuflen, *rbuflen;
     ret  = stat_vol(bitmap, volume, rbuf, rbuflen);
     if (ret == AFP_OK) {
 
-        handle_special_folders( volume );
+        if (!(volume->v_flags & AFPVOL_RO)) {
+            handle_special_folders( volume );
+            savevoloptions( volume);
+        }
 
         /*
          * If you mount a volume twice, the second time the trash appears on
@@ -1725,7 +1768,9 @@ int               ibuflen, *rbuflen;
 
             /* FIXME find db time stamp */
             if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) {
-               LOG (log_error, logtype_afpd, "Fatal error: Unable to get stamp value from CNID backend");
+               LOG (log_error, logtype_afpd, 
+                     "afp_openvol(%s): Fatal error: Unable to get stamp value from CNID backend",
+                     volume->v_path);
                goto openvol_err;
            }
        }
@@ -1921,7 +1966,7 @@ struct vol        *vol;
      * [RS] */
 
     if ( gettimeofday( &tv, 0 ) < 0 ) {
-        LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) );
         return;
     }
     if( utime( vol->v_path, NULL ) < 0 ) {
@@ -2054,13 +2099,13 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
        p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2);
        if ( p == NULL) {
                LOG(log_error, logtype_afpd,"malloc failed");
-               exit (-1);
+               exit (EXITERR_SYS);
        }
 
        q=strdup(folder->name);
        if ( q == NULL) {
                LOG(log_error, logtype_afpd,"malloc failed");
-               exit (-1);
+               exit (EXITERR_SYS);
        }
 
        strcpy(p, vol->v_path);
@@ -2081,6 +2126,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
                    if (ad_mkdir(p, folder->mode)) {
                        LOG(log_debug, logtype_afpd,"Creating '%s' failed in %s: %s", p, vol->v_path, strerror(errno));
                        free(p);
+                       free(q);
                        return -1;
                     }
                    ret = 0;
@@ -2093,6 +2139,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
                if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR,
                        O_RDWR|O_CREAT, 0666, &ad) < 0) {
                        free (p);
+                       free(q);
                        return (-1);
                }
                if ((ad_get_HF_flags( &ad ) & O_CREAT) ) {
@@ -2106,7 +2153,14 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
                ad_getattr(&ad, &attr);
                attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE );
                ad_setattr(&ad, attr);
-    
+#if 0          
+               /* do the same with the finder info */
+               if (ad_entry(&ad, ADEID_FINDERI)) {
+                       memcpy(&attr, ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, sizeof(attr));
+                       attr   |= htons(FINDERINFO_INVISIBLE);
+                       memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr));
+               }
+#endif    
                ad_flush( &ad, ADFLAGS_HF );
                ad_close( &ad, ADFLAGS_HF );
        }
@@ -2127,3 +2181,118 @@ static void handle_special_folders (const struct vol * vol)
        }
 }
 
+/*
+ * 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.
+ */
+static int savevoloptions (const struct vol *vol)
+{
+    char buf[16348];
+    char item[MAXPATHLEN];
+    int fd;
+    int ret = 0;
+    struct flock lock;
+    const _vol_opt_name *op = &vol_opt_names[0];
+    const _vol_opt_name *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;
+    }
+
+    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));
+
+    snprintf(item, sizeof(item), "CNIDDBDPORT:%u\n", Cnid_port);
+    strlcat(buf, item, 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));
+
+    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) {
+       LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
+       goto done;
+   }
+   ftruncate(fd, strlen(buf));
+
+done:
+   lock.l_type = F_UNLCK;
+   fcntl(fd, F_SETLK, &lock);
+   close (fd);
+   return ret;
+}