X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Ffiledir.c;h=7adbeed61c94e9fb02bfa80ed75f21b8e8e9912b;hp=56cbaccffff2d32d59697fb6acad396589284bca;hb=d3dff4ba4b8db3131a16641d35a6554be5fb5160;hpb=be9876310c25cc3faaa72db9b12064a96a1caa70 diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 56cbaccf..7adbeed6 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "directory.h" #include "dircache.h" @@ -218,7 +219,8 @@ int check_name(const struct vol *vol, char *name) move and rename sdir:oldname to curdir:newname in volume vol special care is needed for lock */ -static int moveandrename(const struct vol *vol, +static int moveandrename(const AFPObj *obj, + struct vol *vol, struct dir *sdir, int sdir_fd, char *oldname, @@ -237,10 +239,6 @@ static int moveandrename(const struct vol *vol, cnid_t id; int cwd_fd = -1; - LOG(log_debug, logtype_afpd, - "moveandrename: [\"%s\"/\"%s\"] -> \"%s\"", - cfrombstr(sdir->d_u_name), oldname, newname); - ad_init(&ad, vol); adp = &ad; adflags = 0; @@ -248,7 +246,9 @@ static int moveandrename(const struct vol *vol, if (!isdir) { if ((oldunixname = strdup(mtoupath(vol, oldname, sdir->d_did, utf8_encoding(vol->v_obj)))) == NULL) return AFPERR_PARAM; /* can't convert */ + AFP_CNID_START("cnid_get"); id = cnid_get(vol->v_cdb, sdir->d_did, oldunixname, strlen(oldunixname)); + AFP_CNID_DONE(); #ifndef HAVE_ATFUNCS /* Need full path */ @@ -263,7 +263,7 @@ static int moveandrename(const struct vol *vol, #ifdef HAVE_ATFUNCS opened = of_findnameat(sdir_fd, &path); #else - opened = of_findname(&path); + opened = of_findname(vol, &path); #endif /* HAVE_ATFUNCS */ if (opened) { @@ -300,7 +300,7 @@ static int moveandrename(const struct vol *vol, ad_getattr(adp, &bshort); ad_close(adp, ADFLAGS_HF); - if ((bshort & htons(ATTRBIT_NORENAME))) { + if (!(vol->v_ignattr & ATTRBIT_NORENAME) && (bshort & htons(ATTRBIT_NORENAME))) { rc = AFPERR_OLOCK; goto exit; } @@ -323,6 +323,15 @@ static int moveandrename(const struct vol *vol, goto exit; } + if (isdir) + LOG(log_debug, logtype_afpd, + "moveandrename(\"%s\" -> \"%s/%s\")", + oldunixname, bdata(curdir->d_fullpath), upath); + else + LOG(log_debug, logtype_afpd, + "moveandrename(\"%s/%s\" -> \"%s/%s\")", + bdata(sdir->d_fullpath), oldunixname, bdata(curdir->d_fullpath), upath); + /* source == destination. we just silently accept this. */ if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) { if (strcmp(oldname, newname) == 0) { @@ -346,10 +355,10 @@ static int moveandrename(const struct vol *vol, if ( !isdir ) { path.st_valid = 1; path.st_errno = errno; - if (of_findname(&path)) { + if (of_findname(vol, &path)) { rc = AFPERR_EXIST; /* was AFPERR_BUSY; */ } else { - rc = renamefile(vol, sdir_fd, oldunixname, upath, newname, adp ); + rc = renamefile(vol, curdir, sdir_fd, oldunixname, upath, newname, adp ); if (rc == AFP_OK) of_rename(vol, opened, sdir, oldname, curdir, newname); } @@ -378,7 +387,18 @@ static int moveandrename(const struct vol *vol, } /* fix up the catalog entry */ + AFP_CNID_START("cnid_update"); cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath)); + AFP_CNID_DONE(); + + /* Send FCE event */ + if (isdir) { + fce_register(obj, FCE_DIR_MOVE, fullpathname(upath), oldunixname); + } else { + bstring srcpath = bformat("%s/%s", bdata(sdir->d_fullpath), oldunixname); + fce_register(obj, FCE_FILE_MOVE, fullpathname(upath), bdata(srcpath)); + bdestroy(srcpath); + } } exit: @@ -456,7 +476,7 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size return AFP_OK; /* newname == oldname same dir */ } - rc = moveandrename(vol, sdir, -1, oldname, newname, isdir); + rc = moveandrename(obj, vol, sdir, -1, oldname, newname, isdir); if ( rc == AFP_OK ) { setvoltime(obj, vol ); } @@ -464,6 +484,83 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size return( rc ); } +/* + * Recursivley delete vetoed files and directories if the volume option is set + * + * @param vol (r) volume handle + * @param upath (r) path of directory + * + * If the volume option delete veto files is set, this function recursively scans the + * directory "upath" for vetoed files and tries deletes these, the it will try to delete + * the directory. That may fail if the directory contains normal files that aren't vetoed. + * + * @returns 0 if the directory upath and all of its contents were deleted, otherwise -1. + * If the volume option is not set it returns -1. + */ +int delete_vetoed_files(struct vol *vol, const char *upath, bool in_vetodir) +{ + EC_INIT; + DIR *dp = NULL; + struct dirent *de; + struct stat sb; + int pwd = -1; + bool vetoed; + + if (!(vol->v_flags & AFPVOL_DELVETO)) + return -1; + + EC_NEG1( pwd = open(".", O_RDONLY)); + EC_ZERO( chdir(upath) ); + EC_NULL( dp = opendir(".") ); + + while ((de = readdir(dp))) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + + if (stat(de->d_name, &sb) != 0) { + LOG(log_error, logtype_afpd, "delete_vetoed_files(\"%s/%s\"): %s", + upath, de->d_name, strerror(errno)); + EC_EXIT_STATUS(AFPERR_DIRNEMPT); + } + + if (in_vetodir || veto_file(vol->v_veto, de->d_name)) + vetoed = true; + else + vetoed = false; + + if (vetoed) { + LOG(log_debug, logtype_afpd, "delete_vetoed_files(\"%s/%s\"): deleting vetoed file", + upath, de->d_name); + switch (sb.st_mode & S_IFMT) { + case S_IFDIR: + /* recursion */ + EC_ZERO( delete_vetoed_files(vol, de->d_name, vetoed)); + break; + case S_IFREG: + case S_IFLNK: + EC_ZERO( netatalk_unlink(de->d_name) ); + break; + default: + break; + } + } + } + + EC_ZERO_LOG( fchdir(pwd) ); + pwd = -1; + EC_ZERO_LOG( rmdir(upath) ); + +EC_CLEANUP: + if (dp) + closedir(dp); + if (pwd != -1) { + if (fchdir(pwd) != 0) + ret = -1; + } + + EC_EXIT; +} + /* ------------------------------- */ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { @@ -508,7 +605,9 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size if (rmdir(upath) != 0) { switch (errno) { case ENOTEMPTY: - return AFPERR_DIRNEMPT; + if (delete_vetoed_files(vol, upath, false) != 0) + return AFPERR_DIRNEMPT; + break; case EACCES: return AFPERR_ACCESS; default: @@ -521,11 +620,17 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size delcnid = deldir->d_did; dir_remove(vol, deldir); } - if (delcnid == CNID_INVALID) + if (delcnid == CNID_INVALID) { + AFP_CNID_START("cnid_get"); delcnid = cnid_get(vol->v_cdb, curdir->d_did, upath, strlen(upath)); - if (delcnid != CNID_INVALID) + AFP_CNID_DONE(); + } + if (delcnid != CNID_INVALID) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, delcnid); - fce_register_delete_dir(upath); + AFP_CNID_DONE(); + } + fce_register(obj, FCE_DIR_DELETE, fullpathname(upath), NULL); } else { /* we have to cache this, the structs are lost in deletcurdir*/ /* but we need the positive returncode to send our event */ @@ -533,10 +638,10 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size if ((dname = bstrcpy(curdir->d_u_name)) == NULL) return AFPERR_MISC; if ((rc = deletecurdir(vol)) == AFP_OK) - fce_register_delete_dir(cfrombstr(dname)); + fce_register(obj, FCE_DIR_DELETE, fullpathname(cfrombstr(dname)), NULL); bdestroy(dname); } - } else if (of_findname(s_path)) { + } else if (of_findname(vol, s_path)) { rc = AFPERR_BUSY; } else { /* it's a file st_valid should always be true @@ -547,7 +652,7 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size rc = AFPERR_NOOBJ; } else { if ((rc = deletefile(vol, -1, upath, 1)) == AFP_OK) { - fce_register_delete_file( s_path ); + fce_register(obj, FCE_FILE_DELETE, fullpathname(upath), NULL); if (vol->v_tm_used < s_path->st.st_size) vol->v_tm_used = 0; else @@ -582,8 +687,10 @@ char *absupath(const struct vol *vol, struct dir *dir, char *u) return NULL; if (bcatcstr(path, u) != BSTR_OK) return NULL; - if (path->slen > MAXPATHLEN) + if (path->slen > MAXPATHLEN) { + bdestroy(path); return NULL; + } LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path)); @@ -690,7 +797,7 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* This does the work */ LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)", oldname, newname, isdir); - rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir); + rc = moveandrename(obj, vol, sdir, sdir_fd, oldname, newname, isdir); if ( rc == AFP_OK ) { char *upath = mtoupath(vol, newname, pdid, utf8_encoding(obj)); @@ -703,8 +810,8 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U if (!isdir && !vol_unix_priv(vol)) { int admode = ad_mode("", 0777) | vol->v_fperm; - setfilmode(upath, admode, NULL, vol->v_umask); - vol->vfs->vfs_setfilmode(vol, upath, admode, NULL); + setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL); + vol->vfs->vfs_setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL); } setvoltime(obj, vol ); }