]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/directory.c
/tmp/log
[netatalk.git] / etc / afpd / directory.c
index 3843493acb23351b4d74063d1540c1c7ce918a01..8464aad3b49abed72a595e2c49b97d4154639d49 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.42 2002-10-11 14:18:27 didg Exp $
+ * $Id: directory.c,v 1.56 2003-01-12 14:39:58 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -60,6 +60,7 @@ char *strchr (), *strrchr ();
 #include "unix.h"
 
 struct dir     *curdir;
+int             afp_errno;
 
 #define SENTINEL (&sentinel)
 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
@@ -99,9 +100,10 @@ u_int32_t   did;
 
 
     /* check for 0 did */
-    if (!did)
+    if (!did) {
+        afp_errno = AFPERR_PARAM;
         return NULL;
-
+    }
     if ( did == DIRDID_ROOT_PARENT ) {
         if (!rootpar.d_did)
             rootpar.d_did = DIRDID_ROOT_PARENT;
@@ -110,6 +112,7 @@ u_int32_t   did;
     }
 
     dir = vol->v_root;
+    afp_errno = AFPERR_NOOBJ;
     while ( dir != SENTINEL ) {
         if (dir->d_did == did)
             return dir->d_m_name ? dir : NULL;
@@ -144,7 +147,8 @@ u_int32_t   did;
         return ret;
 
     id = did;
-    if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL) {
+    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) ) {
+        afp_errno = AFPERR_NOOBJ;
         return NULL;
     }
     ptr = path + MAXPATHLEN;
@@ -159,13 +163,17 @@ u_int32_t did;
         if (ret != NULL) {
             break;
         }
-        if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL)
+        if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL) {
+            afp_errno = AFPERR_NOOBJ;
             return NULL;
+        }
         mpath = utompath(vol, upath);
         len = strlen(mpath) + 1;
         pathlen += len;
-        if (pathlen > 255)
+        if (pathlen > 255) {
+            afp_errno = AFPERR_PARAM;
             return NULL;
+        }
         strcpy(ptr - len, mpath);
         ptr -= len;
     }
@@ -436,7 +444,6 @@ struct dir  *dir;
  * process. It's fixable within afpd if fnctl_lock, doable with smb and
  * next to impossible for nfs and local filesystem access.
  */
 static void dir_invalidate( vol, dir )
 const struct vol *vol;
 struct dir *dir;
@@ -811,19 +818,44 @@ char      **cpath;
     static struct path ret;
 
     char               *data, *p;
-    char        *u;
     int                        extend = 0;
     int                        len;
-       int                     olen = 0;
-       
+    u_int32_t   hint;
+    u_int16_t   len16;
+    int         size = 0;
+    char        sep;
+               
     data = *cpath;
-    if ( *data++ != 2 ) {                      /* path type */
+    afp_errno = AFPERR_NOOBJ;
+    switch (ret.m_type = *data) { /* path type */
+    case 2:
+       data++;
+       len = (unsigned char) *data++;
+       size = 2;
+       sep = 0;
+       break;
+    case 3:
+       if (afp_version >= 30) {
+           data++;
+           memcpy(&hint, data, sizeof(hint));
+           hint = ntohl(hint);
+           data += sizeof(hint);
+           
+           memcpy(&len16, data, sizeof(len16));
+           len = ntohs(len16);
+           data += 2;
+           size = 7;
+           sep = 0; /* '/';*/
+           break;
+        }
+        /* else it's an error */
+    default:
+        afp_errno = AFPERR_PARAM;
         return( NULL );
+    
     }
-    len = (unsigned char) *data++;
-    *cpath += len + 2;
+    *cpath += len + size;
     *path = '\0';
-    u = NULL;
     ret.m_name = path;
     ret.st_errno = 0;
     ret.st_valid = 0;
@@ -831,45 +863,29 @@ char      **cpath;
         if ( len == 0 ) {
             if ( !extend && movecwd( vol, dir ) < 0 ) {
                /* it's tricky:
-                  movecwd failed so dir is not there anymore.
+                  movecwd failed some of dir path are not there anymore.
                   FIXME Is it true with other errors?
-                  if path == '\0' ==> the cpath parameter is that dir,
-                  and maybe we are trying to recreate it! So we can't 
-                  fail here.
-                  
+                  so we remove dir from the cache 
                */
-                   if ( dir->d_did == DIRDID_ROOT_PARENT) 
-                               return NULL;                    
-               cdir = dir->d_parent;
+               if (dir->d_did == DIRDID_ROOT_PARENT) 
+                   return NULL;
+               if (afp_errno == AFPERR_ACCESS)
+                   return NULL;                
+
                dir_invalidate(vol, dir);
-               if (*path != '\0' || u == NULL) {
-                       /* FIXME: if path != '\0' then extend != 0 ?
-                        * u == NUL ==> cpath is something like:
-                        * toto\0\0\0
-                       */
-                       return NULL;
-               }
-               if (movecwd(vol, cdir) < 0) {
-                       printf("can't change to parent\n");
-                       return NULL; /* give up the whole tree is out of synch*/
-               }
-                               /* restore the previous token */
-                       strncpy(path, u, olen);
-                       path[olen] = '\0';
+               return NULL;
             }
-            if (!ret.st_valid || *path == '\0') {
+            if (*path == '\0') {
                ret.u_name = ".";
             }               
             return &ret;
         }
 
-        if ( *data == '\0' ) {
+        if (*data == sep ) {
             data++;
             len--;
         }
-       u = NULL;
-
-        while ( *data == '\0' && len > 0 ) {
+        while (*data == sep && len > 0 ) {
             if ( dir->d_parent == NULL ) {
                 return NULL;
             }
@@ -880,11 +896,7 @@ char       **cpath;
 
         /* would this be faster with strlen + strncpy? */
         p = path;
-        if (len > 0) {
-               u = data;
-               olen = len;
-               }        
-        while ( *data != '\0' && len > 0 ) {
+        while ( *data != sep && len > 0 ) {
             *p++ = *data++;
             len--;
         }
@@ -901,7 +913,7 @@ char        **cpath;
             if ( !extend ) {
                 cdir = dir->d_child;
                 while (cdir) {
-                    if ( strcasecmp( cdir->d_m_name, path ) == 0 ) {
+                    if ( strcmp( cdir->d_m_name, path ) == 0 ) {
                         break;
                     }
                     cdir = (cdir == dir->d_child->d_prev) ? NULL :
@@ -917,7 +929,10 @@ char       **cpath;
                        /* dir is not valid anymore 
                           we delete dir from the cache and abort.
                        */
-                       dir_invalidate(vol, dir);
+                       if ( dir->d_did != DIRDID_ROOT_PARENT && 
+                             (afp_errno != AFPERR_ACCESS)) {
+                           dir_invalidate(vol, dir);
+                       }
                         return NULL;
                     }
                     cdir = extenddir( vol, dir, &ret );
@@ -928,6 +943,7 @@ char        **cpath;
             }
 
             if ( cdir == NULL ) {
+
                 if ( len > 0 ) {
                     return NULL;
                 }
@@ -956,6 +972,7 @@ struct dir  *dir;
         return( 0 );
     }
     if ( dir->d_did == DIRDID_ROOT_PARENT) {
+        afp_errno = AFPERR_PARAM;
         return( -1 );
     }
 
@@ -963,19 +980,36 @@ struct dir        *dir;
     *p-- = '\0';
     *p = '.';
     for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
-        *--p = '/';
         u = d->d_u_name;
         n = strlen( u );
+        if (p -n -1 < path) {
+            afp_errno = AFPERR_PARAM;
+            return -1;
+        }
+        *--p = '/';
         p -= n;
         strncpy( p, u, n );
     }
     if ( d != curdir ) {
-        *--p = '/';
         n = strlen( vol->v_path );
+        if (p -n -1 < path) {
+            afp_errno = AFPERR_PARAM;
+            return -1;
+        }
+        *--p = '/';
         p -= n;
         strncpy( p, vol->v_path, n );
     }
     if ( chdir( p ) < 0 ) {
+        switch (errno) {
+        case EACCES:
+        case EPERM:
+            afp_errno = AFPERR_ACCESS;
+            break;
+        default:
+            afp_errno = AFPERR_NOOBJ;
+        
+        }
         return( -1 );
     }
     curdir = dir;
@@ -1012,6 +1046,7 @@ char *p;
    (".", curdir)
    (name, dir) with curdir:name == dir, from afp_enumerate
 */
+
 int getdirparams(const struct vol *vol,
                  u_int16_t bitmap, struct path *s_path,
                  struct dir *dir, 
@@ -1019,11 +1054,12 @@ int getdirparams(const struct vol *vol,
 {
     struct maccess     ma;
     struct adouble     ad;
-    char               *data, *nameoff = NULL;
+    char               *data, *l_nameoff = NULL, *utf_nameoff = NULL;
     int                        bit = 0, isad = 0;
     u_int32_t           aint;
     u_int16_t          ashort;
-    int             ret;
+    int                 ret;
+    u_int32_t           utf8 = 0;
     struct stat *st = &s_path->st;
     char *upath = s_path->u_name;
     
@@ -1114,7 +1150,7 @@ int getdirparams(const struct vol *vol,
 
         case DIRPBIT_LNAME :
             if (dir->d_m_name) /* root of parent can have a null name */
-                nameoff = data;
+                l_nameoff = data;
             else
                 memset(data, 0, sizeof(u_int16_t));
             data += sizeof( u_int16_t );
@@ -1170,14 +1206,27 @@ int getdirparams(const struct vol *vol,
             /* Client has requested the ProDOS information block.
                Just pass back the same basic block for all
                directories. <shirsch@ibm.net> */
-        case DIRPBIT_PDINFO :                    /* ProDOS Info Block */
-            *data++ = 0x0f;
-            *data++ = 0;
-            ashort = htons( 0x0200 );
-            memcpy( data, &ashort, sizeof( ashort ));
-            data += sizeof( ashort );
-            memset( data, 0, sizeof( ashort ));
-            data += sizeof( ashort );
+        case DIRPBIT_PDINFO :                    
+            if (afp_version >= 30) { /* UTF8 name */
+                utf8 = kTextEncodingUTF8;
+                if (dir->d_m_name) /* root of parent can have a null name */
+                    utf_nameoff = data;
+                else
+                    memset(data, 0, sizeof(u_int16_t));
+                data += sizeof( u_int16_t );
+                aint = 0;
+                memcpy(data, &aint, sizeof( aint ));
+                data += sizeof( aint );
+            }
+            else { /* ProDOS Info Block */
+                *data++ = 0x0f;
+                *data++ = 0;
+                ashort = htons( 0x0200 );
+                memcpy( data, &ashort, sizeof( ashort ));
+                data += sizeof( ashort );
+                memset( data, 0, sizeof( ashort ));
+                data += sizeof( ashort );
+            }
             break;
 
         default :
@@ -1189,16 +1238,15 @@ int getdirparams(const struct vol *vol,
         bitmap = bitmap>>1;
         bit++;
     }
-    if ( nameoff ) {
+    if ( l_nameoff ) {
         ashort = htons( data - buf );
-        memcpy( nameoff, &ashort, sizeof( ashort ));
-
-        if ((aint = strlen( dir->d_m_name )) > MACFILELEN)
-            aint = MACFILELEN;
-
-        *data++ = aint;
-        memcpy( data, dir->d_m_name, aint );
-        data += aint;
+        memcpy( l_nameoff, &ashort, sizeof( ashort ));
+        data = set_name(data, dir->d_m_name, 0);
+    }
+    if ( utf_nameoff ) {
+        ashort = htons( data - buf );
+        memcpy( utf_nameoff, &ashort, sizeof( ashort ));
+        data = set_name(data, dir->d_m_name, utf8);
     }
     if ( isad ) {
         ad_close( &ad, ADFLAGS_HF );
@@ -1225,7 +1273,7 @@ int               ibuflen, *rbuflen;
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
 
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
@@ -1236,7 +1284,7 @@ int               ibuflen, *rbuflen;
     ibuf += sizeof( int );
 
     if (( dir = dirlookup( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+        return afp_errno;
     }
 
     memcpy( &bitmap, ibuf, sizeof( bitmap ));
@@ -1244,7 +1292,7 @@ int               ibuflen, *rbuflen;
     ibuf += sizeof( bitmap );
 
     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-        return( AFPERR_NOOBJ );
+        return afp_errno;
     }
 
     if ( *path->m_name != '\0' ) {
@@ -1271,6 +1319,7 @@ int               ibuflen, *rbuflen;
 */
 
 struct path Cur_Path = {
+    0,
     "",  /* mac name */
     ".", /* unix name */
     0,  /* stat is not set */
@@ -1535,9 +1584,10 @@ int setdirparams(const struct vol *vol,
            ProDOS information block.  Skip over the data and
            report nothing amiss. <shirsch@ibm.net> */
         case DIRPBIT_PDINFO :
-            buf += 6;
-            break;
-
+            if (afp_version < 30) {
+                buf += 6;
+                break;
+            }
         default :
             err = AFPERR_BITMAP;
             goto setdirparam_done;
@@ -1595,7 +1645,7 @@ int               ibuflen, *rbuflen;
 
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
@@ -1604,19 +1654,12 @@ int             ibuflen, *rbuflen;
 
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( did );
-    if (( dir = dirlookup( vol, did )) == NULL ) {
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
         return( AFPERR_NOOBJ );
     }
 
-    if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
-        switch( errno ) {
-        case EACCES:
-            return( AFPERR_ACCESS );
-        case EEXIST:                           /* FIXME this one is impossible? */
-            return( AFPERR_EXIST );
-        default:
-            return( AFPERR_NOOBJ );
-        }
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+        return afp_errno;
     }
     /* FIXME check done elswhere? cname was able to move curdir to it! */
     if (*s_path->m_name == '\0')
@@ -1651,6 +1694,7 @@ int               ibuflen, *rbuflen;
     if (of_stat(s_path) < 0) {
         return AFPERR_MISC;
     }
+    curdir->offcnt++;
     if ((dir = adddir( vol, curdir, s_path)) == NULL) {
         return AFPERR_MISC;
     }
@@ -1660,7 +1704,7 @@ int               ibuflen, *rbuflen;
     }
 
     memset(&ad, 0, sizeof(ad));
-    if (ad_open( "", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
+    if (ad_open( ".", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
                  O_RDWR|O_CREAT, 0666, &ad ) < 0)  {
         if (vol_noadouble(vol))
             goto createdir_done;
@@ -1695,9 +1739,9 @@ const int noadouble;
     struct dir         *parent;
     char                *buf;
     int                        len, err;
-    
+        
     /* existence check moved to afp_moveandrename */
-    if ( rename( src, dst ) < 0 ) {
+    if ( unix_rename( src, dst ) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOOBJ );
@@ -1724,27 +1768,17 @@ const int noadouble;
     }
 
     memset(&ad, 0, sizeof(ad));
-    if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            if (noadouble) {
-                len = strlen(newname);
-                goto renamedir_done;
-            }
-            return( AFPERR_NOOBJ );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        default :
-            return( AFPERR_PARAM );
-        }
-    }
     len = strlen( newname );
-    ad_setentrylen( &ad, ADEID_NAME, len );
-    memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
-    ad_flush( &ad, ADFLAGS_HF );
-    ad_close( &ad, ADFLAGS_HF );
-
-renamedir_done:
+    /* rename() succeeded so we need to update our tree even if we can't open
+     * .Parent
+    */
+    if ( !ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad)) {
+        ad_setentrylen( &ad, ADEID_NAME, len );
+        memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
+        ad_flush( &ad, ADFLAGS_HF );
+        ad_close( &ad, ADFLAGS_HF );
+    }
+    
     if (dir->d_m_name == dir->d_u_name)
         dir->d_u_name = NULL;
 
@@ -1899,7 +1933,7 @@ int pathlen;
     }
 
     if ( movecwd( vol, curdir->d_parent ) < 0 ) {
-        return( AFPERR_NOOBJ );
+        return afp_errno;
     }
 
     if ( rmdir(fdir->d_u_name) < 0 ) {
@@ -1937,48 +1971,66 @@ int             ibuflen, *rbuflen;
     char               *name;
     u_int32_t           id;
     int                        len, sfunc;
-
+    int         utf8 = 0;
+    
     ibuf++;
     sfunc = (unsigned char) *ibuf++;
     memcpy( &id, ibuf, sizeof( id ));
 
     id = ntohl(id);
+    *rbuflen = 0;
 
     if ( id != 0 ) {
         switch ( sfunc ) {
         case 1 :
+        case 3 :/* unicode */
             if (( pw = getpwuid( id )) == NULL ) {
-                *rbuflen = 0;
                 return( AFPERR_NOITEM );
             }
             name = pw->pw_name;
             break;
 
         case 2 :
+        case 4 : /* unicode */
             if (( gr = (struct group *)getgrgid( id )) == NULL ) {
-                *rbuflen = 0;
                 return( AFPERR_NOITEM );
             }
             name = gr->gr_name;
             break;
 
         default :
-            *rbuflen = 0;
             return( AFPERR_PARAM );
         }
-
+        switch ( sfunc ) {
+        case 3:
+        case 4:
+            if (afp_version < 30) {
+                return( AFPERR_PARAM );
+            }
+            utf8 = 1;
+            /* map to unicode */
+            break;            
+        }
         len = strlen( name );
 
     } else {
         len = 0;
         name = NULL;
     }
-
-    *rbuf++ = len;
+    if (utf8) {
+        u_int16_t tp = htons(len);
+        memcpy(rbuf, &tp, sizeof(tp));
+        rbuf += sizeof(tp);
+        *rbuflen += 2;
+    }
+    else {
+        *rbuf++ = len;
+        *rbuflen += 1;
+    }
     if ( len > 0 ) {
         memcpy( rbuf, name, len );
     }
-    *rbuflen = len + 1;
+    *rbuflen += len;
     return( AFP_OK );
 }
 
@@ -1989,16 +2041,33 @@ int             ibuflen, *rbuflen;
 {
     struct passwd      *pw;
     struct group       *gr;
-    int                        len, sfunc;
-    u_int32_t           id;
+    int             len, sfunc;
+    u_int32_t       id;
+    u_int16_t       ulen;
 
     ibuf++;
     sfunc = (unsigned char) *ibuf++;
-    len = (unsigned char) *ibuf++;
+    switch ( sfunc ) {
+    case 1 : 
+    case 2 : /* unicode */
+        memcpy(&ulen, ibuf, sizeof(ulen));
+        len = ntohs(ulen);
+        ibuf += 2;
+        break;
+    case 3 :
+    case 4 :
+        len = (unsigned char) *ibuf++;
+        break;
+    default :
+        *rbuflen = 0;
+        return( AFPERR_PARAM );
+    }
+
     ibuf[ len ] = '\0';
 
     if ( len != 0 ) {
         switch ( sfunc ) {
+        case 1 : /* unicode */
         case 3 :
             if (( pw = (struct passwd *)getpwnam( ibuf )) == NULL ) {
                 *rbuflen = 0;
@@ -2007,6 +2076,7 @@ int               ibuflen, *rbuflen;
             id = pw->pw_uid;
             break;
 
+        case 2 : /* unicode */
         case 4 :
             if (( gr = (struct group *)getgrnam( ibuf )) == NULL ) {
                 *rbuflen = 0;
@@ -2014,9 +2084,6 @@ int               ibuflen, *rbuflen;
             }
             id = gr->gr_gid;
             break;
-        default :
-            *rbuflen = 0;
-            return( AFPERR_PARAM );
         }
     } else {
         id = 0;
@@ -2086,24 +2153,19 @@ int             ibuflen, *rbuflen;
     memcpy(&vid, ibuf, sizeof(vid));
     ibuf += sizeof( vid );
 
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
     memcpy(&did, ibuf, sizeof(did));
     ibuf += sizeof(did);
 
-    if (( parentdir = dirlookup( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( parentdir = dirlookup( vol, did )) ) {
+        return afp_errno;
     }
 
-    if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
-        switch( errno ) {
-        case EACCES:
-            return( AFPERR_ACCESS );
-        default:
-            return( AFPERR_NOOBJ );
-        }
+    if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
+        return afp_errno;
     }
 
     if ( *path->m_name != '\0' ) {