]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/volume.c
MFH: Set the volume creation time from the first stat call done in openvol -before...
[netatalk.git] / etc / afpd / volume.c
index 83e5ffbae8786f9d5b2eeb719df7d24f9997ef51..68fb8351b3cd744458e63d49525d396073e1d1e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.c,v 1.19 2002-01-18 05:19:26 jmarcus Exp $
+ * $Id: volume.c,v 1.36.2.5 2003-09-18 19:24:54 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -81,6 +81,7 @@ static int            lastvid = 0;
 static char            *Trash = "\02\024Network Trash Folder";
 #endif /* CNID_DB */
 static struct extmap   *extmap = NULL, *defextmap = NULL;
+static int              extmap_cnt;
 
 #define VOLOPT_ALLOW      0  /* user allow list */
 #define VOLOPT_DENY       1  /* user deny list */
@@ -104,11 +105,16 @@ m=u -> map both ways
 #define VOLOPT_VETO      10  /* list of veto filespec */
 
 #ifdef FORCE_UIDGID
+#warning UIDGID
+#include "uid.h"
+
 #define VOLOPT_FORCEUID  11  /* force uid for username x */
 #define VOLOPT_FORCEGID  12  /* force gid for group x */
-#define VOLOPT_MAX       12
+#define VOLOPT_UMASK     13
+#define VOLOPT_MAX       13
 #else /* normally, there are only 9 possible options */
-#define VOLOPT_MAX       10
+#define VOLOPT_UMASK     11
+#define VOLOPT_MAX       11
 #endif /* FORCE_UIDGID */
 
 #define VOLOPT_NUM        (VOLOPT_MAX + 1)
@@ -280,19 +286,26 @@ static __inline__ char *get_codepage_path(const char *path, const char *name)
     }
 
     /* debug: show which codepage directory we are using */
-    LOG(log_debug, logtype_default, "using codepage directory: %s", page);
+    LOG(log_debug, logtype_afpd, "using codepage directory: %s", page);
 
     return page;
 }
 
 /* handle all the options. tmp can't be NULL. */
 static void volset(struct vol_option *options, char *volname, int vlen,
-                   const char *nlspath, const char *tmp)
+                  const char *nlspath, const char *tmp, AFPObj *obj,
+                  struct passwd *pwd)
 {
     char *val;
 
+    LOG(log_debug, logtype_afpd, "Parsing volset %s", tmp);
+
     val = strchr(tmp, ':');
-    if (optionok(tmp, "allow:", val)) {
+    if (!val) {
+        /* we'll assume it's a volume name. */
+        strncpy(volname, tmp, vlen);
+
+    } else if (optionok(tmp, "allow:", val)) {
         if (options[VOLOPT_ALLOW].c_value)
             free(options[VOLOPT_ALLOW].c_value);
         options[VOLOPT_ALLOW].c_value = strdup(val + 1);
@@ -364,17 +377,23 @@ static void volset(struct vol_option *options, char *volname, int vlen,
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
             else if (strcasecmp(p, "dropkludge") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
+            else if (strcasecmp(p, "nofileid") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID;
 
             p = strtok(NULL, ",");
         }
 
 #ifdef CNID_DB
     } else if (optionok(tmp, "dbpath:", val)) {
+       char t[MAXPATHLEN + 1];
         if (options[VOLOPT_DBPATH].c_value)
             free(options[VOLOPT_DBPATH].c_value);
 
-        options[VOLOPT_DBPATH].c_value = strdup(val + 1);
+       volxlate(obj, t, MAXPATHLEN, val, pwd, NULL);
+       options[VOLOPT_DBPATH].c_value = strdup(t + 1);
 #endif /* CNID_DB */
+    } else if (optionok(tmp, "umask:", val)) {
+       options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8);
     } else if (optionok(tmp, "mapchars:",val)) {
         if (options[VOLOPT_MAPCHARS].c_value)
             free(options[VOLOPT_MAPCHARS].c_value);
@@ -399,13 +418,10 @@ static void volset(struct vol_option *options, char *volname, int vlen,
 
 #endif /* FORCE_UIDGID */
 
-    } else if (val) {
+    } else {
         /* ignore unknown options */
-        LOG(log_debug, logtype_default, "ignoring unknown volume option: %s", tmp);
+        LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
 
-    } else {
-        /* we'll assume it's a volume name. */
-        strncpy(volname, tmp, vlen);
     }
 }
 
@@ -438,18 +454,18 @@ static int creatvol(const char *path, char *name, struct vol_option *options)
 
     if (( volume =
                 (struct vol *)calloc(1, sizeof( struct vol ))) == NULL ) {
-        LOG(log_error, logtype_default, "creatvol: malloc: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
         return -1;
     }
     if (( volume->v_name =
                 (char *)malloc( vlen + 1 )) == NULL ) {
-        LOG(log_error, logtype_default, "creatvol: malloc: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
         free(volume);
         return -1;
     }
     if (( volume->v_path =
                 (char *)malloc( strlen( path ) + 1 )) == NULL ) {
-        LOG(log_error, logtype_default, "creatvol: malloc: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
         free(volume->v_name);
         free(volume);
         return -1;
@@ -487,6 +503,9 @@ static int creatvol(const char *path, char *name, struct vol_option *options)
             volume->v_dbpath = strdup(options[VOLOPT_DBPATH].c_value);
 #endif /* CNID_DB */
 
+       if (options[VOLOPT_UMASK].i_value)
+           volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
+
 #ifdef FORCE_UIDGID
 
         if (options[VOLOPT_FORCEUID].c_value) {
@@ -519,7 +538,7 @@ FILE        *fp;
     int                c;
 
     p = buf;
-    while ((( c = getc( fp )) != EOF ) && ( size > 0 )) {
+    while ((EOF != ( c = getc( fp )) ) && ( size > 0 )) {
         if ( c == '\n' || c == '\r' ) {
             *p++ = '\n';
             break;
@@ -579,26 +598,38 @@ char              *ext, *type, *creator;
 int                    user;
 {
     struct extmap      *em;
+    int                 cnt;
 
-    for ( em = extmap; em; em = em->em_next ) {
-        if ( strdiacasecmp( em->em_ext, ext ) == 0 ) {
+    if (extmap == NULL) {
+        if (( extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
+            LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) );
+            return;
+        }
+    }
+    ext++;
+    for ( em = extmap, cnt = 0; em->em_ext; em++, cnt++) {
+        if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) {
             break;
         }
     }
 
-    if ( em == NULL ) {
-        if (( em =
-                    (struct extmap *)malloc( sizeof( struct extmap ))) == NULL ) {
-            LOG(log_error, logtype_default, "setextmap: malloc: %s", strerror(errno) );
+    if ( em->em_ext == NULL ) {
+        if (!(extmap  = realloc( extmap, sizeof( struct extmap ) * (cnt +2))) ) {
+            LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) );
             return;
         }
-        em->em_next = extmap;
-        extmap = em;
+        (extmap +cnt +1)->em_ext = NULL;
+        em = extmap +cnt;
     } else if ( !user ) {
         return;
     }
+    if (em->em_ext)
+       free(em->em_ext);
 
-    strcpy( em->em_ext, ext );
+    if (!(em->em_ext = strdup(  ext))) {
+        LOG(log_error, logtype_afpd, "setextmap: strdup: %s", strerror(errno) );
+        return;
+    }
 
     if ( *type == '\0' ) {
         memcpy(em->em_type, "????", sizeof( em->em_type ));
@@ -610,12 +641,35 @@ int                       user;
     } else {
         memcpy(em->em_creator, creator, sizeof( em->em_creator ));
     }
+}
+
+/* -------------------------- */
+static int extmap_cmp(const void *map1, const void *map2)
+{
+    const struct extmap *em1 = map1;
+    const struct extmap *em2 = map2;
+    return strdiacasecmp(em1->em_ext, em2->em_ext);
+}
 
-    if ( strcmp( ext, "." ) == 0 ) {
-        defextmap = em;
+static void sortextmap( void)
+{
+    struct extmap      *em;
+
+    extmap_cnt = 0;
+    if ((em = extmap) == NULL) {
+        return;
+    }
+    while (em->em_ext) {
+        em++;
+        extmap_cnt++;
+    }
+    if (extmap_cnt) {
+        qsort(extmap, extmap_cnt, sizeof(struct extmap), extmap_cmp);
+        defextmap = extmap;
     }
 }
 
+
 /*
  * Read a volume configuration file and add the volumes contained within to
  * the global volume list.  If p2 is non-NULL, the file that is opened is
@@ -651,7 +705,7 @@ struct passwd *pwent;
         strcat( path, p2 );
     }
 
-    if (( fp = fopen( path, "r" )) == NULL ) {
+    if (NULL == ( fp = fopen( path, "r" )) ) {
         return( -1 );
     }
 
@@ -673,7 +727,8 @@ struct passwd *pwent;
                                    path + VOLOPT_DEFAULT_LEN) < 0)
                         break;
                     volset(save_options, tmp, sizeof(tmp) - 1,
-                           obj->options.nlspath, path + VOLOPT_DEFAULT_LEN);
+                          obj->options.nlspath, path + VOLOPT_DEFAULT_LEN,
+                          obj, pwent);
                 }
             }
             break;
@@ -695,6 +750,10 @@ struct passwd *pwent;
                 strcat( tmp, "/" );
                 strcat( tmp, p );
             }
+           /* Tag a user's home directory with their umask.  Note, this will
+            * be overwritten if the user actually specifies a umask: option
+            * for a '~' volume. */
+           save_options[VOLOPT_UMASK].i_value = obj->options.save_mask;
             /* fall through */
 
         case '/' :
@@ -731,7 +790,7 @@ struct passwd *pwent;
                     break;
 
                 volset(options, volname, sizeof(volname) - 1,
-                       obj->options.nlspath, tmp);
+                      obj->options.nlspath, tmp, obj, pwent);
             }
 
             /* check allow/deny lists:
@@ -769,8 +828,9 @@ struct passwd *pwent;
         }
     }
     volfree(save_options, NULL);
+    sortextmap();
     if ( fclose( fp ) != 0 ) {
-        LOG(log_error, logtype_default, "readvolfile: fclose: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
     }
     return( 0 );
 }
@@ -892,6 +952,7 @@ int         *buflen;
         ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
         memcpy(ad_entry( &ad, ADEID_NAME ), slash,
                ad_getentrylen( &ad, ADEID_NAME ));
+        ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, st->st_mtime);
         ad_flush(&ad, ADFLAGS_HF);
     }
 
@@ -916,10 +977,11 @@ int               *buflen;
 
         switch ( bit ) {
         case VOLPBIT_ATTR :
-#ifdef CNID_DB
-            ashort = VOLPBIT_ATTR_FILEID;
-#else /* CNID_DB */
             ashort = 0;
+#ifdef CNID_DB
+            if (0 == (vol->v_flags & AFPVOL_NOFILEID)) {
+                ashort = VOLPBIT_ATTR_FILEID;
+            }
 #endif /* CNID_DB */
             /* check for read-only.
              * NOTE: we don't actually set the read-only flag unless
@@ -928,6 +990,7 @@ int         *buflen;
             if ((vol->v_flags & AFPVOL_RO) ||
                     ((utime(vol->v_path, NULL) < 0) && (errno == EROFS)))
                 ashort |= VOLPBIT_ATTR_RO;
+                ashort |= VOLPBIT_ATTR_CATSEARCH;
             ashort = htons(ashort);
             memcpy(data, &ashort, sizeof( ashort ));
             data += sizeof( ashort );
@@ -1058,8 +1121,8 @@ int       ibuflen, *rbuflen;
     data = rbuf + 5;
     for ( vcnt = 0, volume = volumes; volume; volume = volume->v_next ) {
         if ( stat( volume->v_path, &st ) < 0 ) {
-            LOG(log_info, logtype_default, "afp_getsrvrparms: stat %s: %s",
-                    volume->v_path, strerror(errno) );
+            LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s",
+                volume->v_path, strerror(errno) );
             continue;          /* can't access directory */
         }
         if (!S_ISDIR(st.st_mode)) {
@@ -1086,7 +1149,7 @@ int       ibuflen, *rbuflen;
     *rbuflen = data - rbuf;
     data = rbuf;
     if ( gettimeofday( &tv, 0 ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
         *rbuflen = 0;
         return AFPERR_PARAM;
     }
@@ -1152,7 +1215,7 @@ int               ibuflen, *rbuflen;
 
     if (( volume->v_flags & AFPVOL_OPEN  ) == 0 ) {
         if ((dir = dirnew(strlen(volume->v_name) + 1)) == NULL) {
-            LOG(log_error, logtype_default, "afp_openvol: malloc: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) );
             ret = AFPERR_MISC;
             goto openvol_err;
         }
@@ -1162,6 +1225,9 @@ int               ibuflen, *rbuflen;
         volume->v_dir = volume->v_root = dir;
         volume->v_flags |= AFPVOL_OPEN;
     }
+#ifdef FORCE_UIDGID
+    set_uidgid ( volume );
+#endif /* FORCE_UIDGID */
 
     if ( stat( volume->v_path, &st ) < 0 ) {
         ret = AFPERR_PARAM;
@@ -1177,17 +1243,17 @@ int             ibuflen, *rbuflen;
     bitmap = htons( bitmap );
     memcpy(rbuf, &bitmap, sizeof( bitmap ));
 
-    curdir = volume->v_dir;
     if ( chdir( volume->v_path ) < 0 ) {
         ret = AFPERR_PARAM;
         goto openvol_err;
     }
+    curdir = volume->v_dir;
 
 #ifdef CNID_DB
     if (volume->v_dbpath)
-        volume->v_db = cnid_open (volume->v_dbpath);
-    if (volume->v_db == 0)
-        volume->v_db = cnid_open (volume->v_path);
+        volume->v_db = cnid_open (volume->v_dbpath, volume->v_umask);
+    if (volume->v_db == NULL)
+        volume->v_db = cnid_open (volume->v_path, volume->v_umask);
 #endif /* CNID_DB */
 
 #ifndef CNID_DB
@@ -1196,7 +1262,7 @@ int               ibuflen, *rbuflen;
      * the desk-top.  That's because the Mac remembers the DID for the
      * trash (even for volumes in different zones, on different servers).
      * Just so this works better, we prime the DID cache with the trash,
-     * fixing the trash at DID 3.
+     * fixing the trash at DID 17.
      */
     p = Trash;
     cname( volume, volume->v_dir, &p );
@@ -1220,7 +1286,7 @@ int               ibuflen, *rbuflen;
     *rbuflen = 0;
     ibuf += 2;
     memcpy(&vid, ibuf, sizeof( vid ));
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
@@ -1231,12 +1297,11 @@ int             ibuflen, *rbuflen;
         }
     }
     if ( ovol != NULL ) {
-        curdir = ovol->v_dir;
-        if ( chdir( ovol->v_path ) < 0 ) {
-            return( AFPERR_PARAM );
+        /* Even if chdir fails, we can't say afp_closevol fails. */
+        if ( chdir( ovol->v_path ) == 0 ) {
+            curdir = ovol->v_dir;
         }
     }
-
     dirfree( vol->v_root );
     vol->v_dir = NULL;
 #ifdef CNID_DB
@@ -1259,30 +1324,73 @@ struct vol *getvolbyvid(const u_int16_t vid )
         return( NULL );
     }
 
+#ifdef FORCE_UIDGID
+    set_uidgid ( vol );
+#endif /* FORCE_UIDGID */
+
     return( vol );
 }
 
+/* ------------------------ */
+static int ext_cmp_key(const void *key, const void *obj)
+{
+    const char          *p = key;
+    const struct extmap *em = obj;
+    return strdiacasecmp(p, em->em_ext);
+}
 struct extmap *getextmap(const char *path)
 {
-    char       *p;
-    struct extmap      *em;
+    char         *p;
+    struct extmap *em;
 
-    if (( p = strrchr( path, '.' )) == NULL ) {
+    if (NULL == ( p = strrchr( path, '.' )) ) {
         return( defextmap );
     }
-
-    for ( em = extmap; em; em = em->em_next ) {
-        if ( strdiacasecmp( em->em_ext, p ) == 0 ) {
-            break;
-        }
-    }
-    if ( em == NULL ) {
+    p++;
+    if (!*p || !extmap_cnt) {
         return( defextmap );
-    } else {
+    }
+    em = bsearch(p, extmap, extmap_cnt, sizeof(struct extmap), ext_cmp_key);
+    if (em) {
         return( em );
+    } else {
+        return( defextmap );
     }
 }
 
+struct extmap *getdefextmap(void)
+{
+    return( defextmap );
+}
+
+/*
+   poll if a volume is changed by other processes.
+*/
+int  pollvoltime(obj)
+AFPObj *obj;
+{
+    struct vol      *vol;
+    struct timeval   tv;
+    struct stat      st;
+    
+    if (!(afp_version > 21 && obj->options.server_notif)) 
+         return 0;
+
+    if ( gettimeofday( &tv, 0 ) < 0 ) 
+         return 0;
+
+    for ( vol = volumes; vol; vol = vol->v_next ) {
+        if ( (vol->v_flags & AFPVOL_OPEN)  && vol->v_time + 30 < tv.tv_sec) {
+            if ( !stat( vol->v_path, &st ) && vol->v_time != st.st_mtime ) {
+                vol->v_time = st.st_mtime;
+                obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
 void setvoltime(obj, vol )
 AFPObj *obj;
 struct vol     *vol;
@@ -1296,7 +1404,7 @@ struct vol        *vol;
      * [RS] */
 
     if ( gettimeofday( &tv, 0 ) < 0 ) {
-        LOG(log_error, logtype_default, "setvoltime: gettimeofday: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) );
         return;
     }
     if( utime( vol->v_path, NULL ) < 0 ) {
@@ -1308,7 +1416,9 @@ struct vol        *vol;
     /* a little granularity */
     if (vol->v_time < tv.tv_sec) {
         vol->v_time = tv.tv_sec;
-        obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
+        if (afp_version > 21 && obj->options.server_notif) {
+            obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
+        }
     }
 }
 
@@ -1328,7 +1438,7 @@ int               ibuflen, *rbuflen;
     memcpy(&bitmap, ibuf, sizeof( bitmap ));
     bitmap = ntohs( bitmap );
 
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         *rbuflen = 0;
         return( AFPERR_PARAM );
     }
@@ -1397,25 +1507,27 @@ int             ibuflen, *rbuflen;
 }
 
 
-int wincheck(struct vol *vol, const char *path)
+int wincheck(const struct vol *vol, const char *path)
 {
-        int len;
+    int len;
 
-        if (!(vol->v_flags & AFPVOL_MSWINDOWS))
-                return 1;
+    if (!(vol->v_flags & AFPVOL_MSWINDOWS))
+        return 1;
 
-        /* empty paths are not allowed */
-        if ((len = strlen(path)) == 0)
-                return 0;
+    /* empty paths are not allowed */
+    if ((len = strlen(path)) == 0)
+        return 0;
 
-        /* leading or trailing whitespaces are not allowed */
-        if ((*path == ' ') || (path[len-1] == ' '))
-                return 0;
+    /* leading or trailing whitespaces are not allowed, carriage returns
+     * and probably other whitespace is okay, tabs are not allowed
+     */
+    if ((path[0] == ' ') || (path[len-1] == ' '))
+        return 0;
 
-        /* certain characters are not allowed */
-        if (strpbrk(path, MSWINDOWS_BADCHARS))
-                return 0;
+    /* certain characters are not allowed */
+    if (strpbrk(path, MSWINDOWS_BADCHARS))
+        return 0;
 
-        /* everything else is okay */
-        return 1;
+    /* everything else is okay */
+    return 1;
 }