]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/desktop.c
Add advanced option "chmod request" controlling ACLs
[netatalk.git] / etc / afpd / desktop.c
index 043c4737b90ffcc60882c138d6f5395ad51dfe89..5c56977acd3fd30e6dea0659b40b68b19ac68898 100644 (file)
 #include <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/logger.h>
+#include <atalk/globals.h>
+#include <atalk/netatalk_conf.h>
+#include <atalk/unix.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/errchk.h>
+
 #include "volume.h"
 #include "directory.h"
 #include "fork.h"
-#include "globals.h"
 #include "desktop.h"
 #include "mangle.h"
 
+#define EXEC_MODE (S_IXGRP | S_IXUSR | S_IXOTH)
+
+int setdeskmode(const struct vol *vol, const mode_t mode)
+{
+    EC_INIT;
+    char               wd[ MAXPATHLEN + 1];
+    struct stat         st;
+    char               modbuf[ 12 + 1], *m;
+    struct dirent      *deskp, *subp;
+    DIR                        *desk, *sub;
+
+    if (!dir_rx_set(mode)) {
+        /* want to remove read and search access to owner it will screw the volume */
+        return -1 ;
+    }
+    if ( getcwd( wd , MAXPATHLEN) == NULL ) {
+        return( -1 );
+    }
+
+    bstring dtpath = bfromcstr(vol->v_dbpath);
+    bcatcstr(dtpath, "/" APPLEDESKTOP);
+
+    EC_NEG1( chdir(cfrombstr(dtpath)) );
+
+    if (( desk = opendir( "." )) == NULL ) {
+        if ( chdir( wd ) < 0 ) {
+            LOG(log_error, logtype_afpd, "setdeskmode: chdir %s: %s", wd, strerror(errno) );
+        }
+        EC_FAIL;
+    }
+    for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
+        if ( strcmp( deskp->d_name, "." ) == 0 ||
+                strcmp( deskp->d_name, ".." ) == 0 || strlen( deskp->d_name ) > 2 ) {
+            continue;
+        }
+        strcpy( modbuf, deskp->d_name );
+        strcat( modbuf, "/" );
+        m = strchr( modbuf, '\0' );
+        if (( sub = opendir( deskp->d_name )) == NULL ) {
+            continue;
+        }
+        for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
+            if ( strcmp( subp->d_name, "." ) == 0 ||
+                    strcmp( subp->d_name, ".." ) == 0 ) {
+                continue;
+            }
+            *m = '\0';
+            strcat( modbuf, subp->d_name );
+            /* XXX: need to preserve special modes */
+            if (lstat(modbuf, &st) < 0) {
+                LOG(log_error, logtype_afpd, "setdeskmode: stat %s: %s",fullpathname(modbuf), strerror(errno) );
+                continue;
+            }
+
+            if (S_ISDIR(st.st_mode)) {
+                if (ochmod(modbuf,
+                           DIRBITS | mode,
+                           &st,
+                           vol_syml_opt(vol) | vol_chmod_opt(vol)
+                        ) < 0 && errno != EPERM) {
+                     LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
+                }
+            } else if (ochmod(modbuf,
+                           mode & ~EXEC_MODE,
+                           &st,
+                           vol_syml_opt(vol) | vol_chmod_opt(vol)
+                        ) < 0 && errno != EPERM) {
+                LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
+            }
+
+        }
+        closedir( sub );
+        /* XXX: need to preserve special modes */
+        if (ochmod(deskp->d_name,
+                   DIRBITS | mode,
+                   NULL,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0 && errno != EPERM) {
+            LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(deskp->d_name), strerror(errno) );
+        }
+    }
+    closedir( desk );
+    if ( chdir( wd ) < 0 ) {
+        LOG(log_error, logtype_afpd, "setdeskmode: chdir %s: %s", wd, strerror(errno) );
+        EC_FAIL;
+    }
+    /* XXX: need to preserve special modes */
+    if (ochmod(bdata(dtpath),
+               DIRBITS | mode,
+               NULL,
+               vol_syml_opt(vol) | vol_chmod_opt(vol)
+            ) < 0 && errno != EPERM) {
+        LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s", bdata(dtpath), strerror(errno));
+    }
+
+EC_CLEANUP:
+    bdestroy(dtpath);
+    EC_EXIT;
+}
+
+int setdeskowner(const struct vol *vol, uid_t uid, gid_t gid)
+{
+    EC_INIT;
+    char               wd[ MAXPATHLEN + 1];
+    char               modbuf[12 + 1], *m;
+    struct dirent      *deskp, *subp;
+    DIR                        *desk, *sub;
+
+    if ( getcwd( wd, MAXPATHLEN ) == NULL ) {
+        return( -1 );
+    }
+
+    bstring dtpath = bfromcstr(vol->v_dbpath);
+    bcatcstr(dtpath, "/" APPLEDESKTOP);
+
+    EC_NEG1( chdir(cfrombstr(dtpath)) );
+    
+    if (( desk = opendir( "." )) == NULL ) {
+        if ( chdir( wd ) < 0 ) {
+            LOG(log_error, logtype_afpd, "setdeskowner: chdir %s: %s", wd, strerror(errno) );
+        }
+        EC_FAIL;
+    }
+    for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
+        if ( strcmp( deskp->d_name, "." ) == 0 ||
+                strcmp( deskp->d_name, ".." ) == 0 ||
+                strlen( deskp->d_name ) > 2 ) {
+            continue;
+        }
+        strcpy( modbuf, deskp->d_name );
+        strcat( modbuf, "/" );
+        m = strchr( modbuf, '\0' );
+        if (( sub = opendir( deskp->d_name )) == NULL ) {
+            continue;
+        }
+        for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
+            if ( strcmp( subp->d_name, "." ) == 0 ||
+                    strcmp( subp->d_name, ".." ) == 0 ) {
+                continue;
+            }
+            *m = '\0';
+            strcat( modbuf, subp->d_name );
+            /* XXX: add special any uid, ignore group bits */
+            if ( chown( modbuf, uid, gid ) < 0 && errno != EPERM ) {
+                LOG(log_error, logtype_afpd, "setdeskown: chown %s: %s", fullpathname(modbuf), strerror(errno) );
+            }
+        }
+        closedir( sub );
+        /* XXX: add special any uid, ignore group bits */
+        if ( chown( deskp->d_name, uid, gid ) < 0 && errno != EPERM ) {
+            LOG(log_error, logtype_afpd, "setdeskowner: chown %s: %s",
+                deskp->d_name, strerror(errno) );
+        }
+    }
+    closedir( desk );
+    if ( chdir( wd ) < 0 ) {
+        LOG(log_error, logtype_afpd, "setdeskowner: chdir %s: %s", wd, strerror(errno) );
+        EC_FAIL;
+    }
+    if (chown(cfrombstr(dtpath), uid, gid ) < 0 && errno != EPERM ) {
+        LOG(log_error, logtype_afpd, "setdeskowner: chown %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
+    }
+
+EC_CLEANUP:
+    bdestroy(dtpath);
+    EC_EXIT;
+}
+
+static void create_appledesktop_folder(const struct vol * vol)
+{
+    bstring olddtpath = NULL, dtpath = NULL;
+    struct stat st;
+    char *cmd_argv[4];
+
+    olddtpath = bfromcstr(vol->v_path);
+    bcatcstr(olddtpath, "/" APPLEDESKTOP);
+
+    dtpath = bfromcstr(vol->v_dbpath);
+    bcatcstr(dtpath, "/" APPLEDESKTOP);
+
+    if (lstat(cfrombstr(dtpath), &st) != 0) {
+
+        become_root();
+
+        if (lstat(cfrombstr(olddtpath), &st) == 0) {
+            cmd_argv[0] = "mv";
+            cmd_argv[1] = bdata(olddtpath);
+            cmd_argv[2] = bdata(dtpath);
+            cmd_argv[3] = NULL;
+            if (run_cmd("mv", cmd_argv) != 0) {
+                LOG(log_error, logtype_afpd, "moving .AppleDesktop from \"%s\" to \"%s\" failed",
+                    bdata(olddtpath), bdata(dtpath));
+                mkdir(cfrombstr(dtpath), 0777);
+            }
+        } else {
+            mkdir(cfrombstr(dtpath), 0777);
+        }
+
+        unbecome_root();
+    }
+
+    bdestroy(dtpath);
+    bdestroy(olddtpath);
+}
 
 int afp_opendt(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
     struct vol *vol;
-    u_int16_t  vid;
+    uint16_t   vid;
 
     ibuf += 2;
 
@@ -48,6 +258,8 @@ int afp_opendt(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size
         return( AFPERR_PARAM );
     }
 
+    create_appledesktop_folder(vol);
+
     memcpy( rbuf, &vid, sizeof(vid));
     *rbuflen = sizeof(vid);
     return( AFP_OK );
@@ -117,8 +329,8 @@ int afp_addicon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
     u_char             fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
     int                        itype, cc = AFP_OK, iovcnt = 0;
     size_t             buflen;
-    u_int32_t           ftype, itag;
-    u_int16_t          bsize, rsize, vid;
+    uint32_t           ftype, itag;
+    uint16_t           bsize, rsize, vid;
 
     buflen = *rbuflen;
     *rbuflen = 0;
@@ -204,42 +416,34 @@ int afp_addicon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
      */
 addicon_err:
     if ( cc < 0 ) {
-        if (obj->proto == AFPPROTO_DSI) {
-            dsi_writeinit(obj->handle, rbuf, buflen);
-            dsi_writeflush(obj->handle);
-        }
+        dsi_writeinit(obj->dsi, rbuf, buflen);
+        dsi_writeflush(obj->dsi);
         return cc;
     }
 
-    switch (obj->proto) {
-    case AFPPROTO_DSI:
-        {
-            DSI *dsi = obj->handle;
+    DSI *dsi = obj->dsi;
 
-            iovcnt = dsi_writeinit(dsi, rbuf, buflen);
+    iovcnt = dsi_writeinit(dsi, rbuf, buflen);
 
-            /* add headers at end of file */
-            if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
-                LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
-                dsi_writeflush(dsi);
-                return AFPERR_PARAM;
-            }
+    /* add headers at end of file */
+    if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
+        LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
+        dsi_writeflush(dsi);
+        return AFPERR_PARAM;
+    }
 
-            if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
-                dsi_writeflush(dsi);
-                return AFPERR_PARAM;
-            }
+    if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
+        LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
+        dsi_writeflush(dsi);
+        return AFPERR_PARAM;
+    }
 
-            while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
-                if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                    LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
-                    dsi_writeflush(dsi);
-                    return AFPERR_PARAM;
-                }
-            }
+    while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
+        if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
+            LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
+            dsi_writeflush(dsi);
+            return AFPERR_PARAM;
         }
-        break;
     }
 
     close( si.sdt_fd );
@@ -292,8 +496,8 @@ static const u_char uicon[] = {
 int afp_geticoninfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
     struct vol *vol;
-    u_char     fcreator[ 4 ], ih[ 12 ];
-    u_int16_t  vid, iindex, bsize;
+    unsigned char      fcreator[ 4 ], ih[ 12 ];
+    uint16_t   vid, iindex, bsize;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -366,7 +570,7 @@ int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
     off_t       offset;
     ssize_t    rc, buflen;
     u_char     fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
-    u_int16_t  vid, bsize, rsize;
+    uint16_t   vid, bsize, rsize;
 
     buflen = *rbuflen;
     *rbuflen = 0;
@@ -441,8 +645,8 @@ int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
 #define min(a,b)       ((a)<(b)?(a):(b))
     rc = min( bsize, rsize );
 
-    if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
-        DSI *dsi = obj->handle;
+    if (buflen < rc) {
+        DSI *dsi = obj->dsi;
         struct stat st;
         off_t size;
 
@@ -451,29 +655,29 @@ int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
             return AFPERR_PARAM;
         }
 
+#ifndef WITH_SENDFILE
         if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
             goto geticon_exit;
+#endif
 
         *rbuflen = buflen;
         /* do to the streaming nature, we have to exit if we encounter
          * a problem. much confusion results otherwise. */
         while (*rbuflen > 0) {
 #ifdef WITH_SENDFILE
-            if (!obj->options.flags & OPTION_DEBUG) {
-                if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
-                    switch (errno) {
-                    case ENOSYS:
-                    case EINVAL:  /* there's no guarantee that all fs support sendfile */
-                        break;
-                    default:
-                        goto geticon_exit;
-                    }
-                }
-                else {
-                    dsi_readdone(dsi);
-                    return AFP_OK;
+            if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize, AFP_OK) < 0) {
+                switch (errno) {
+                case ENOSYS:
+                case EINVAL:  /* there's no guarantee that all fs support sendfile */
+                    break;
+                default:
+                    goto geticon_exit;
                 }
             }
+            else {
+                dsi_readdone(dsi);
+                return AFP_OK;
+            }
 #endif
             buflen = read(si.sdt_fd, rbuf, *rbuflen);
             if (buflen < 0)
@@ -513,8 +717,8 @@ char *dtfile(const struct vol *vol, u_char creator[], char *ext )
     char       *p;
     unsigned int i;
 
-    strcpy( path, vol->v_path );
-    strcat( path, "/.AppleDesktop/" );
+    strcpy( path, vol->v_dbpath );
+    strcat( path, "/" APPLEDESKTOP "/" );
     for ( p = path; *p != '\0'; p++ )
         ;
 
@@ -552,7 +756,7 @@ char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
     char       *m, *u;
     size_t       inplen;
     size_t       outlen;
-    u_int16_t   flags;
+    uint16_t    flags;
         
     if ( *mpath == '\0' ) {
         strcpy(upath, ".");
@@ -591,7 +795,7 @@ char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
 {
     static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
     char        *m, *u;
-    u_int16_t    flags;
+    uint16_t    flags;
     size_t       outlen;
 
     m = mpath;
@@ -626,7 +830,7 @@ utompath_error:
 }
 
 /* ------------------------- */
-static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
+static int ad_addcomment(const AFPObj *obj, struct vol *vol, struct path *path, char *ibuf)
 {
     struct ofork        *of;
     char                *name, *upath;
@@ -638,20 +842,19 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
     clen = min( clen, 199 );
 
     upath = path->u_name;
-    if (check_access(upath, OPENACC_WR ) < 0) {
+    if (check_access(obj, vol, upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
     }
     
     isadir = path_isadir(path);
-    if (isadir || !(of = of_findname(path))) {
-        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+    if (isadir || !(of = of_findname(vol, path))) {
+        ad_init(&ad, vol);
         adp = &ad;
     } else
         adp = of->of_ad;
 
     if (ad_open(adp, upath,
-                ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0),
-                O_CREAT | O_RDWR,
+                ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0) | ADFLAGS_CREATE | ADFLAGS_RDWR,
                 0666) < 0 ) {
         return( AFPERR_ACCESS );
     }
@@ -669,18 +872,18 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
         ad_flush( adp );
     }
-    ad_close_metadata( adp);
+    ad_close(adp, ADFLAGS_HF);
     return( AFP_OK );
 }
 
 /* ----------------------------- */
-int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+int afp_addcomment(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct vol         *vol;
     struct dir         *dir;
     struct path         *path;
-    u_int32_t           did;
-    u_int16_t          vid;
+    uint32_t           did;
+    uint16_t           vid;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -705,7 +908,7 @@ int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
         ibuf++;
     }
 
-    return ad_addcomment(vol, path, ibuf);
+    return ad_addcomment(obj, vol, path, ibuf);
 }
 
 /* -------------------- */
@@ -719,8 +922,8 @@ static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t
 
     upath = path->u_name;
     isadir = path_isadir(path);
-    if (isadir || !(of = of_findname(path))) {
-        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+    if (isadir || !(of = of_findname(vol, path))) {
+        ad_init(&ad, vol);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -730,7 +933,7 @@ static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t
     }
 
     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
-        ad_close_metadata( adp );
+        ad_close(adp, ADFLAGS_HF);
         return AFPERR_NOITEM;
     }
     /*
@@ -738,7 +941,7 @@ static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t
      */
     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
-        ad_close_metadata( adp );
+        ad_close(adp, ADFLAGS_HF);
         return( AFPERR_NOITEM );
     }
 
@@ -746,7 +949,7 @@ static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t
     *rbuf++ = clen;
     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
     *rbuflen = clen + 1;
-    ad_close_metadata( adp);
+    ad_close(adp, ADFLAGS_HF);
 
     return( AFP_OK );
 }
@@ -757,8 +960,8 @@ int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
     struct vol         *vol;
     struct dir         *dir;
     struct path         *s_path;
-    u_int32_t          did;
-    u_int16_t          vid;
+    uint32_t           did;
+    uint16_t           vid;
     
     *rbuflen = 0;
     ibuf += 2;
@@ -783,7 +986,7 @@ int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
 }
 
 /* ----------------------- */
-static int ad_rmvcomment(struct vol *vol, struct path *path)
+static int ad_rmvcomment(const AFPObj *obj, struct vol *vol, struct path *path)
 {
     struct adouble     ad, *adp;
     struct ofork        *of;
@@ -791,18 +994,18 @@ static int ad_rmvcomment(struct vol *vol, struct path *path)
     char               *upath;
 
     upath = path->u_name;
-    if (check_access(upath, OPENACC_WR ) < 0) {
+    if (check_access(obj, vol, upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
     }
 
     isadir = path_isadir(path);
-    if (isadir || !(of = of_findname(path))) {
-        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+    if (isadir || !(of = of_findname(vol, path))) {
+        ad_init(&ad, vol);
         adp = &ad;
     } else
         adp = of->of_ad;
 
-    if ( ad_open(adp, upath, ADFLAGS_HF | (isadir) ? ADFLAGS_DIR : 0, 0) < 0 ) {
+    if ( ad_open(adp, upath, ADFLAGS_HF | ADFLAGS_RDWR | ((isadir) ? ADFLAGS_DIR : 0)) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOITEM );
@@ -817,7 +1020,7 @@ static int ad_rmvcomment(struct vol *vol, struct path *path)
         ad_setentrylen( adp, ADEID_COMMENT, 0 );
         ad_flush( adp );
     }
-    ad_close_metadata( adp);
+    ad_close(adp, ADFLAGS_HF);
     return( AFP_OK );
 }
 
@@ -827,8 +1030,8 @@ int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
     struct vol         *vol;
     struct dir         *dir;
     struct path         *s_path;
-    u_int32_t          did;
-    u_int16_t          vid;
+    uint32_t           did;
+    uint16_t           vid;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -849,5 +1052,5 @@ int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
        return get_afp_errno(AFPERR_NOOBJ);
     }
     
-    return ad_rmvcomment(vol, s_path);
+    return ad_rmvcomment(obj, vol, s_path);
 }