/*
- * $Id: directory.c,v 1.102 2009-09-01 13:55:55 franklahm Exp $
+ * $Id: directory.c,v 1.131 2010-01-26 20:39:52 didg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
#endif
#include <stdio.h>
#include <stdlib.h>
-#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <sys/param.h>
#include <errno.h>
#include <utime.h>
-#include <atalk/adouble.h>
+#include <atalk/adouble.h>
+#include <atalk/vfs.h>
#include <atalk/afp.h>
#include <atalk/util.h>
#include <atalk/cnid.h>
#include <atalk/logger.h>
#include <atalk/uuid.h>
+#include <atalk/unix.h>
#include "directory.h"
#include "desktop.h"
#include "globals.h"
#include "unix.h"
#include "mangle.h"
+#include "hash.h"
#ifdef HAVE_NFSv4_ACLS
extern void addir_inherit_acl(const struct vol *vol);
-#endif
+#endif
-struct dir *curdir;
+/*
+ * Directory caches
+ * ================
+ *
+ * There are currently two cache structures where afpd caches directory information
+ * a) a DID/dirname cache in a hashtable
+ * b) a (red-black) tree with CNIDs as key
+ *
+ * a) is for searching by DID/dirname
+ * b) is for searching by CNID
+ *
+ * Through additional parent, child, previous and next pointers, b) is also used to
+ * represent the on-disk layout of the filesystem. parent and child point to parent
+ * and child directory respectively, linking 2 or more subdirectories in one
+ * directory with previous and next pointers.
+ *
+ * Usage examples, highlighting the main functions:
+ *
+ * a) is eg used in enumerate():
+ * if IS_DIR
+ * dir = dirsearch_byname() // search in cache
+ * if (dir == NULL) // not found
+ * dir = adddir() // add to cache
+ * getdirparams()
+ *
+ * b) is eg used in afp_getfildirparams()
+ * dirlookup() // wrapper for cache and db search
+ * => dir = dirsearch() // search in cache
+ * if (dir) // found
+ * return
+ * else // not found,
+ * cnid_resolve() // resolve with CNID database
+ * cname() // add to cache
+ */
+
+struct dir *curdir;
int afp_errno;
#define SENTINEL (&sentinel)
-static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
- NULL, NULL, NULL, NULL, NULL, 0, 0,
- 0, 0, NULL, NULL, NULL};
-static struct dir rootpar = { SENTINEL, SENTINEL, NULL, 0,
- NULL, NULL, NULL, NULL, NULL, 0, 0,
- 0, 0, NULL, NULL, NULL};
+static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
+ DIRTREE_COLOR_BLACK, /* color */
+ NULL, NULL, /* parent, child */
+ NULL, NULL, /* previous, next */
+ NULL, 0, 0, /* oforks, did, flags */
+ 0, 0, /* ctime, offcnt */
+ NULL, NULL, NULL}; /* mname, uname, ucs2-name */
+static struct dir rootpar = { SENTINEL, SENTINEL, NULL,
+ 0,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, 0, 0,
+ 0, 0,
+ NULL, NULL, NULL};
/* (from IM: Toolbox Essentials)
* dirFinderInfo (DInfo) fields:
* frPutAway: 4 home directory ID
*/
+static struct dir *
+vol_tree_root(const struct vol *vol, u_int32_t did)
+{
+ struct dir *dir;
+
+ if (vol->v_curdir && vol->v_curdir->d_did == did) {
+ dir = vol->v_curdir;
+ }
+ else {
+ dir = vol->v_root;
+ }
+ return dir;
+}
+
/*
* redid did assignment for directories. now we use red-black trees.
* how exciting.
*/
struct dir *
- dirsearch( vol, did )
- const struct vol *vol;
-u_int32_t did;
+dirsearch(const struct vol *vol, u_int32_t did)
{
- struct dir *dir;
+ struct dir *dir;
/* check for 0 did */
rootpar.d_child = vol->v_dir;
return( &rootpar );
}
-#if 0
- /* XXX would be nice to check against curdir but we need to keep its volume */
- if (vol->curdir && curdir->d_did == did) {
- dir = curdir;
- }
- else {
- dir = vol->v_root;
- }
-#endif
- dir = vol->v_root;
+
+ dir = vol_tree_root(vol, did);
afp_errno = AFPERR_NOOBJ;
while ( dir != SENTINEL ) {
}
/* ------------------- */
-#ifdef ATACC
-int path_isadir(struct path *o_path)
-{
- return o_path->d_dir != NULL;
-#if 0
- return o_path->m_name == '\0' || /* we are in a it */
- !o_path->st_valid || /* in cache but we can't chdir in it */
- (!o_path->st_errno && S_ISDIR(o_path->st.st_mode)); /* not in cache an can't chdir */
-#endif
-}
-#endif
-
int get_afp_errno(const int param)
{
if (afp_errno != AFPERR_DID1)
struct dir *
dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
{
-struct dir *dir = NULL;
+ struct dir *dir = NULL;
if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
struct dir key;
hnode_t *hn;
-
+
key.d_parent = cdir;
key.d_u_name = name;
- hn = hash_lookup(vol->v_hash, &key);
- if (hn) {
- dir = hnode_get(hn);
- }
+ hn = hash_lookup(vol->v_hash, &key);
+ if (hn) {
+ dir = hnode_get(hn);
+ }
}
return dir;
-}
+}
/* -----------------------------------------
- * if did is not in the cache resolve it with cnid
- *
+ * if did is not in the cache resolve it with cnid
+ *
* FIXME
* OSX call it with bogus id, ie file ID not folder ID,
* and we are really bad in this case.
*/
struct dir *
- dirlookup( vol, did )
- const struct vol *vol;
-u_int32_t did;
+dirlookup( struct vol *vol, u_int32_t did)
{
struct dir *ret;
- char *upath;
- cnid_t id, cnid;
+ char *upath;
+ cnid_t id, cnid;
static char path[MAXPATHLEN + 1];
size_t len, pathlen;
char *ptr;
char *mpath;
int utf8;
size_t maxpath;
-
+
ret = dirsearch(vol, did);
if (ret != NULL || afp_errno == AFPERR_PARAM)
return ret;
if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
||
NULL == (mpath = utompath(vol, upath, cnid, utf8))
- ) {
+ ) {
afp_errno = AFPERR_NOOBJ;
return NULL;
}
strcpy(ptr - len, mpath);
ptr -= len;
}
-
+
/* fill the cache, another place where we know about the path type */
if (utf8) {
u_int16_t temp16;
u_int32_t temp;
- ptr -= 2;
+ ptr -= 2;
temp16 = htons(pathlen);
memcpy(ptr, &temp16, sizeof(temp16));
temp = htonl(kTextEncodingUTF8);
- ptr -= 4;
+ ptr -= 4;
memcpy(ptr, &temp, sizeof(temp));
ptr--;
*ptr = 3;
/* cname is not efficient */
if (cname( vol, ret, &ptr ) == NULL )
return NULL;
-
+
return dirsearch(vol, did);
}
/* child addition/removal */
-static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
+static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
{
if (!a->d_child)
a->d_child = b;
else {
b->d_next = a->d_child;
b->d_prev = b->d_next->d_prev;
- b->d_next->d_prev = b;
- b->d_prev->d_next = b;
+ b->d_next->d_prev = b;
+ b->d_prev->d_next = b;
}
- if (!hash_alloc_insert(vol->v_hash, b, b)) {
+ if (!hash_alloc_insert(vol->v_hash, b, b)) {
LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
}
-}
+}
static void dirchildremove(struct dir *a,struct dir *b)
-{
- if (a->d_child == b)
+{
+ if (a->d_child == b)
a->d_child = (b == b->d_next) ? NULL : b->d_next;
b->d_next->d_prev = b->d_prev;
b->d_prev->d_next = b->d_next;
/* --------------------------- */
/* rotate the tree to the left */
-static void dir_leftrotate(vol, dir)
-struct vol *vol;
-struct dir *dir;
+static void dir_leftrotate(struct vol *vol, struct dir *dir)
{
struct dir *right = dir->d_right;
/* rotate the tree to the right */
-static void dir_rightrotate(vol, dir)
-struct vol *vol;
-struct dir *dir;
+static void dir_rightrotate(struct vol *vol, struct dir *dir)
{
struct dir *left = dir->d_left;
#if 0
/* recolor after a removal */
-static struct dir *dir_rmrecolor(vol, dir)
- struct vol *vol;
-struct dir *dir;
+static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
{
struct dir *leaf;
/* right leaf has black end nodes */
if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
- (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
+ (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
dir = dir->d_back; /* ascend */
} else {
/* left leaf has black end nodes */
if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
- (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
+ (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
dir = dir->d_back; /* ascend */
} else {
LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
}
else {
- hash_delete(vol->v_hash, hn);
+ hash_delete(vol->v_hash, hn);
}
}
* different. actually, it has to worry about a bunch of things that
* insertion doesn't care about. */
-static void dir_remove( const struct vol *vol _U_, struct dir *dir)
+static void dir_remove( struct vol *vol, struct dir *dir)
{
#ifdef REMOVE_NODES
struct ofork *of, *last;
struct dir *node, *leaf;
#endif /* REMOVE_NODES */
-
+
if (!dir || (dir == SENTINEL))
return;
-
+
/* i'm not sure if it really helps to delete stuff. */
dir_hash_del(vol, dir);
-#ifndef REMOVE_NODES
+ vol->v_curdir = NULL;
+#ifndef REMOVE_NODES
dirfreename(dir);
dir->d_m_name = NULL;
dir->d_u_name = NULL;
}
/* we want to free node, but we also want to free the data in dir.
- * currently, that's d_name and the directory traversal bits.
- * we just copy the necessary bits and then fix up all the
- * various pointers to the directory. needless to say, there are
- * a bunch of places that store the directory struct. */
+ * currently, that's d_name and the directory traversal bits.
+ * we just copy the necessary bits and then fix up all the
+ * various pointers to the directory. needless to say, there are
+ * a bunch of places that store the directory struct. */
if (node != dir) {
struct dir save, *tmp;
rootpar.d_child = vol->v_dir;
} else {
/* if we aren't the root directory, we have parents and
- * siblings to worry about */
+ * siblings to worry about */
if (dir->d_parent->d_child == node)
dir->d_parent->d_child = dir;
dir->d_next->d_prev = dir;
*
* FIXME what about opened forks with refs to it?
* it's an afp specs violation because you can't delete
- * an opened forks. Now afpd doesn't care about forks opened by other
+ * an opened forks. Now afpd doesn't care about forks opened by other
* 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;
+static void dir_invalidate( struct vol *vol, struct dir *dir)
{
if (curdir == dir) {
/* v_root can't be deleted */
}
/* ------------------------------------ */
-static struct dir *dir_insert(vol, dir)
- const struct vol *vol;
-struct dir *dir;
+static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
{
- struct dir *pdir;
+ struct dir *pdir;
- pdir = vol->v_root;
+ pdir = vol_tree_root(vol, dir->d_did);
while (pdir->d_did != dir->d_did ) {
if ( pdir->d_did > dir->d_did ) {
if ( pdir->d_left == SENTINEL ) {
struct dirent *de;
int ret;
static u_int32_t did = 0;
- static char cname[MAXPATHLEN];
- static char lname[MAXPATHLEN];
- ucs2_t u2_path[MAXPATHLEN];
- ucs2_t u2_dename[MAXPATHLEN];
- char *tmp, *savepath;
+ static char cname[MAXPATHLEN];
+ static char lname[MAXPATHLEN];
+ ucs2_t u2_path[MAXPATHLEN];
+ ucs2_t u2_dename[MAXPATHLEN];
+ char *tmp, *savepath;
if (!(vol->v_flags & AFPVOL_CASEINSEN))
return -1;
-
+
if (veto_file(ENUMVETO, path->u_name))
- return -1;
+ return -1;
savepath = path->u_name;
/* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
- if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, strlen(path->u_name), u2_path, sizeof(u2_path)) )
+ if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
/*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
if (NULL == check_dirent(vol, de->d_name))
continue;
- if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, strlen(de->d_name), u2_dename, sizeof(u2_dename)) )
+ if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
continue;
if (strcasecmp_w( u2_path, u2_dename) == 0) {
ret = 0;
break;
}
- else
+ else
path->u_name = tmp;
}
* as a side-effect, movecwd to that point and return the new dir
*/
static struct dir *
- extenddir( vol, dir, path )
-struct vol *vol;
-struct dir *dir;
-struct path *path;
+extenddir(struct vol *vol, struct dir *dir, struct path *path)
{
path->d_dir = NULL;
if (of_stat( path ) != 0 ) {
if (!(vol->v_flags & AFPVOL_CASEINSEN))
return NULL;
- else if(caseenumerate(vol, path, dir) != 0)
+ else if(caseenumerate(vol, path, dir) != 0)
return(NULL);
}
return( dir );
}
-/* -------------------
- system rmdir with afp error code.
- ENOENT is not an error.
- */
-int netatalk_rmdir(const char *name)
-{
- if (rmdir(name) < 0) {
- switch ( errno ) {
- case ENOENT :
- break;
- case ENOTEMPTY :
- return AFPERR_DIRNEMPT;
- case EPERM:
- case EACCES :
- return AFPERR_ACCESS;
- case EROFS:
- return AFPERR_VLOCK;
- default :
- return AFPERR_PARAM;
- }
- }
- return AFP_OK;
-}
-
/* -------------------------
appledouble mkdir afp error code.
*/
return AFP_OK;
}
-/* -------------------
- system unlink with afp error code.
- ENOENT is not an error.
- */
-int netatalk_unlink(const char *name)
-{
- if (unlink(name) < 0) {
- switch (errno) {
- case ENOENT :
- break;
- case EROFS:
- return AFPERR_VLOCK;
- case EPERM:
- case EACCES :
- return AFPERR_ACCESS;
- default :
- return AFPERR_PARAM;
- }
- }
- return AFP_OK;
-}
-
/* ------------------- */
static int deletedir(char *dir)
{
char path[MAXPATHLEN + 1];
DIR *dp;
- struct dirent *de;
+ struct dirent *de;
struct stat st;
size_t len;
int err = AFP_OK;
{
char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
DIR *dp;
- struct dirent *de;
+ struct dirent *de;
struct stat st;
struct utimbuf ut;
size_t slen, dlen;
/* doesn't exist or the path is too long. */
if (((slen = strlen(src)) > sizeof(spath) - 2) ||
- ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
- ((dp = opendir(src)) == NULL))
+ ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
+ ((dp = opendir(src)) == NULL))
return AFPERR_PARAM;
/* try to create the destination directory */
strcat(spath, "/");
slen++;
srem = sizeof(spath) - slen -1;
-
+
strcpy(dpath, dst);
strcat(dpath, "/");
dlen++;
/* --- public functions follow --- */
/* NOTE: we start off with at least one node (the root directory). */
-static struct dir *dirinsert( vol, dir )
- struct vol *vol;
-struct dir *dir;
+static struct dir *dirinsert(struct vol *vol, struct dir *dir)
{
struct dir *node;
dir->d_color = DIRTREE_COLOR_RED;
/* parent of this node has to be black. if the parent node
- * is red, then we have a grandparent. */
+ * is red, then we have a grandparent. */
while ((dir != vol->v_root) &&
- (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
+ (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
/* are we on the left tree? */
if (dir->d_back == dir->d_back->d_back->d_left) {
node = dir->d_back->d_back->d_right; /* get the right node */
/* ---------------------------- */
struct dir *
- adddir( vol, dir, path)
-struct vol *vol;
-struct dir *dir;
-struct path *path;
+adddir(struct vol *vol, struct dir *dir, struct path *path)
{
- struct dir *cdir, *edir;
- int upathlen;
+ struct dir *cdir, *edir;
+ int upathlen;
char *name;
char *upath;
struct stat *st;
int deleted;
+ struct adouble ad;
+ struct adouble *adp = NULL;
cnid_t id;
upath = path->u_name;
st = &path->st;
upathlen = strlen(upath);
- id = get_id(vol, NULL, st, dir->d_did, upath, upathlen);
+ /* get_id needs adp for reading CNID from adouble file */
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
+ adp = &ad;
+
+ id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
+
+ if (adp)
+ ad_close_metadata(adp);
+
if (id == 0) {
return NULL;
}
if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
return NULL;
}
- name = path->m_name;
+ name = path->m_name;
if ((cdir = dirnew(name, upath)) == NULL) {
LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
return NULL;
}
- if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, strlen(path->m_name), &cdir->d_m_name_ucs2)) {
- LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
- cdir->d_m_name_ucs2 = NULL;
+ if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, -1, (char **)&cdir->d_m_name_ucs2)) {
+ LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
+ cdir->d_m_name_ucs2 = NULL;
}
cdir->d_did = id;
- someone else have moved the directory.
- it's a symlink inside the share.
- it's an ID reused, the old directory was deleted but not
- the cnid record and the server've reused the inode for
- the new dir.
- for HASH (we should get ride of HASH)
+ the cnid record and the server've reused the inode for
+ the new dir.
+ for HASH (we should get ride of HASH)
- someone else have moved the directory.
- it's an ID reused as above
- it's a hash duplicate and we are in big trouble
free(dir->d_u_name);
}
if (dir->d_m_name_ucs2)
- free(dir->d_m_name_ucs2);
+ free(dir->d_m_name_ucs2);
free(dir->d_m_name);
}
-void dirfree( dir )
-struct dir *dir;
+void dirfree(struct dir *dir)
{
if (!dir || (dir == SENTINEL))
return;
}
/* --------------------------------------------
- * most of the time mac name and unix name are the same
-*/
+ * most of the time mac name and unix name are the same
+ */
struct dir *dirnew(const char *m_name, const char *u_name)
{
struct dir *dir;
/* ------------------ */
static hash_val_t hash_fun_dir(const void *key)
{
-const struct dir *k = key;
+ const struct dir *k = key;
static unsigned long randbox[] = {
- 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
- 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
- 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
- 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
+ 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
+ 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
+ 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
+ 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
};
- const unsigned char *str = k->d_u_name;
- hash_val_t acc = 0;
+ const unsigned char *str = (unsigned char *)(k->d_u_name);
+ hash_val_t acc = k->d_parent->d_did;
while (*str) {
- acc ^= randbox[(*str + acc) & 0xf];
- acc = (acc << 1) | (acc >> 31);
- acc &= 0xffffffffU;
- acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
- acc = (acc << 2) | (acc >> 30);
- acc &= 0xffffffffU;
+ acc ^= randbox[(*str + acc) & 0xf];
+ acc = (acc << 1) | (acc >> 31);
+ acc &= 0xffffffffU;
+ acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
+ acc = (acc << 2) | (acc >> 30);
+ acc &= 0xffffffffU;
}
return acc;
}
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+static hash_val_t hash_fun2_dir(const void *key)
+{
+ const struct dir *k = key;
+ const char *data = k->d_u_name;
+ int len = strlen(k->d_u_name);
+ hash_val_t hash = k->d_parent->d_did, tmp;
+
+ int rem = len & 3;
+ len >>= 2;
+
+ /* Main loop */
+ for (;len > 0; len--) {
+ hash += get16bits (data);
+ tmp = (get16bits (data+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2*sizeof (uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem) {
+ case 3: hash += get16bits (data);
+ hash ^= hash << 16;
+ hash ^= data[sizeof (uint16_t)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (data);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += *data;
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
+
/* ---------------- */
static int hash_comp_dir(const void *key1, const void *key2)
{
-const struct dir *k1 = key1;
-const struct dir *k2 = key2;
+ const struct dir *k1 = key1;
+ const struct dir *k2 = key2;
return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
}
hash_t *
dirhash(void)
{
- return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun_dir);
+ return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
}
/* ------------------ */
-static struct path *invalidate (const struct vol *vol, struct dir *dir, struct path *ret)
+static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
{
/* it's tricky:
movecwd failed some of dir path are not there anymore.
FIXME Is it true with other errors?
- so we remove dir from the cache
+ so we remove dir from the cache
*/
if (dir->d_did == DIRDID_ROOT_PARENT)
return NULL;
if (afp_errno == AFPERR_ACCESS) {
if ( movecwd( vol, dir->d_parent ) < 0 ) {
- return NULL;
+ return NULL;
}
/* FIXME should we set these?, don't need to call stat() after:
ret->st_valid = 1;
ret->st_errno = EACCES;
- */
- ret->m_name = dir->d_m_name;
- ret->u_name = dir->d_u_name;
- ret->d_dir = dir;
- return ret;
+ */
+ ret->m_name = dir->d_m_name;
+ ret->u_name = dir->d_u_name;
+ ret->d_dir = dir;
+ return ret;
} else if (afp_errno == AFPERR_NOOBJ) {
- if ( movecwd( vol, dir->d_parent ) < 0 ) {
- return NULL;
- }
- strcpy(ret->m_name, dir->d_m_name);
- if (dir->d_m_name == dir->d_u_name) {
- ret->u_name = ret->m_name;
- }
- else {
- size_t tp = strlen(ret->m_name)+1;
-
- ret->u_name = ret->m_name +tp;
- strcpy(ret->u_name, dir->d_u_name);
- }
- /* FIXME should we set :
- ret->st_valid = 1;
- ret->st_errno = ENOENT;
- */
- dir_invalidate(vol, dir);
- return ret;
+ if ( movecwd( vol, dir->d_parent ) < 0 ) {
+ return NULL;
+ }
+ strcpy(ret->m_name, dir->d_m_name);
+ if (dir->d_m_name == dir->d_u_name) {
+ ret->u_name = ret->m_name;
+ }
+ else {
+ size_t tp = strlen(ret->m_name)+1;
+
+ ret->u_name = ret->m_name +tp;
+ strcpy(ret->u_name, dir->d_u_name);
+ }
+ /* FIXME should we set :
+ ret->st_valid = 1;
+ ret->st_errno = ENOENT;
+ */
+ dir_invalidate(vol, dir);
+ return ret;
}
dir_invalidate(vol, dir);
return NULL;
}
/* -------------------------------------------------- */
-/* cname
- return
- if it's a filename:
- in extenddir:
- compute unix name
- stat the file or errno
- return
- filename
- curdir: filename parent directory
-
- if it's a dirname:
- not in the cache
- in extenddir
- compute unix name
- stat the dir or errno
- return
- if chdir error
- dirname
- curdir: dir parent directory
- sinon
- dirname: ""
- curdir: dir
- in the cache
- return
- if chdir error
- dirname
- curdir: dir parent directory
- else
- dirname: ""
- curdir: dir
-
+/* cname
+ return
+ if it's a filename:
+ in extenddir:
+ compute unix name
+ stat the file or errno
+ return
+ filename
+ curdir: filename parent directory
+
+ if it's a dirname:
+ not in the cache
+ in extenddir
+ compute unix name
+ stat the dir or errno
+ return
+ if chdir error
+ dirname
+ curdir: dir parent directory
+ sinon
+ dirname: ""
+ curdir: dir
+ in the cache
+ return
+ if chdir error
+ dirname
+ curdir: dir parent directory
+ else
+ dirname: ""
+ curdir: dir
+
*/
struct path *
-cname( vol, dir, cpath )
-const struct vol *vol;
-struct dir *dir;
-char **cpath;
+cname(struct vol *vol, struct dir *dir, char **cpath)
{
- struct dir *cdir, *scdir=NULL;
- static char path[ MAXPATHLEN + 1];
+ struct dir *cdir, *scdir=NULL;
+ static char path[ MAXPATHLEN + 1];
static struct path ret;
- char *data, *p;
- int extend = 0;
- int len;
+ char *data, *p;
+ int extend = 0;
+ int len;
u_int32_t hint;
u_int16_t len16;
int size = 0;
memset(&ret, 0, sizeof(ret));
switch (ret.m_type = *data) { /* path type */
case 2:
- data++;
- len = (unsigned char) *data++;
- size = 2;
- sep = 0;
- if (afp_version >= 30) {
- ret.m_type = 3;
- toUTF8 = 1;
- }
- break;
+ data++;
+ len = (unsigned char) *data++;
+ size = 2;
+ sep = 0;
+ if (afp_version >= 30) {
+ ret.m_type = 3;
+ toUTF8 = 1;
+ }
+ 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;
+ 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:
return invalidate(vol, dir, &ret );
}
if (*path == '\0') {
- ret.u_name = ".";
- ret.d_dir = dir;
- }
+ ret.u_name = ".";
+ ret.d_dir = dir;
+ }
return &ret;
}
}
/* short cut bits by chopping off a trailing \0. this also
- makes the traversal happy w/ filenames at the end of the
- cname. */
+ makes the traversal happy w/ filenames at the end of the
+ cname. */
if (len == 1)
len--;
if (afp_version >= 30) {
char *t;
cnid_t fileid;
-
+
if (toUTF8) {
- static char temp[ MAXPATHLEN + 1];
+ static char temp[ MAXPATHLEN + 1];
if (dir->d_did == DIRDID_ROOT_PARENT) {
/*
}
}
/* check for OS X mangled filename :( */
-
+
t = demangle_osx(vol, path, dir->d_did, &fileid);
if (t != path) {
ret.u_name = t;
- /* duplicate work but we can't reuse all convert_char we did in demangle_osx
+ /* duplicate work but we can't reuse all convert_char we did in demangle_osx
* flags weren't the same
*/
- if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
- /* at last got our view of mac name */
- strcpy(path,t);
- }
+ if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
+ /* at last got our view of mac name */
+ strcpy(path,t);
+ }
}
}
if (ret.u_name == NULL) {
ucs2_t *tmpname;
cdir = dir->d_child;
scdir = NULL;
- if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
- (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
- CH_UCS2, path, strlen(path), (char **)&tmpname) )
+ if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
+ (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
+ CH_UCS2, path, -1, (char **)&tmpname) )
{
while (cdir) {
if (!cdir->d_m_name_ucs2) {
}
if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
- break;
+ break;
}
if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
- scdir = cdir;
+ scdir = cdir;
}
cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
}
free(tmpname);
}
else {
-noucsfallback:
+ noucsfallback:
if (dir->d_did == DIRDID_ROOT_PARENT) {
- /*
- root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
- must check against the volume name.
- */
- if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
- cdir = vol->v_dir;
- else
- cdir = NULL;
+ /*
+ root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
+ must check against the volume name.
+ */
+ if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
+ cdir = vol->v_dir;
+ else
+ cdir = NULL;
}
else {
- cdir = dirsearch_byname(vol, dir, ret.u_name);
+ cdir = dirsearch_byname(vol, dir, ret.u_name);
}
}
-
+
if (cdir == NULL && scdir != NULL) {
cdir = scdir;
/* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
if ( cdir == NULL ) {
++extend;
/* if dir == curdir it always succeed,
- even if curdir is deleted.
- it's not a pb because it will fail in extenddir
+ even if curdir is deleted.
+ it's not a pb because it will fail in extenddir
*/
if ( movecwd( vol, dir ) < 0 ) {
- /* dir is not valid anymore
+ /* dir is not valid anymore
we delete dir from the cache and abort.
*/
if ( dir->d_did == DIRDID_ROOT_PARENT) {
- afp_errno = AFPERR_NOOBJ;
- return NULL;
+ afp_errno = AFPERR_NOOBJ;
+ return NULL;
}
if (afp_errno == AFPERR_ACCESS)
- return NULL;
+ return NULL;
dir_invalidate(vol, dir);
return NULL;
}
}
} else {
- dir = cdir;
+ dir = cdir;
*path = '\0';
}
} /* for (;;) */
/*
* Move curdir to dir, with a possible chdir()
*/
-int movecwd( vol, dir)
-const struct vol *vol;
-struct dir *dir;
+int movecwd(struct vol *vol, struct dir *dir)
{
char path[MAXPATHLEN + 1];
- struct dir *d;
- char *p, *u;
- int n;
+ struct dir *d;
+ char *p, *u;
+ int n;
if ( dir == curdir ) {
return( 0 );
*p = '.';
for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
u = d->d_u_name;
- if (!u) {
- /* parent directory is deleted */
- afp_errno = AFPERR_NOOBJ;
- return -1;
- }
+ if (!u) {
+ /* parent directory is deleted */
+ afp_errno = AFPERR_NOOBJ;
+ return -1;
+ }
n = strlen( u );
if (p -n -1 < path) {
afp_errno = AFPERR_PARAM;
break;
default:
afp_errno = AFPERR_NOOBJ;
-
+
}
return( -1 );
}
- curdir = dir;
+ vol->v_curdir = curdir = dir;
return( 0 );
}
* We can't use unix file's perm to support Apple's inherited protection modes.
* If we aren't the file's owner we can't change its perms when moving it and smb
* nfs,... don't even try.
-*/
-#define AFP_CHECK_ACCESS
+ */
+#define AFP_CHECK_ACCESS
int check_access(char *path, int mode)
{
#ifdef AFP_CHECK_ACCESS
-struct maccess ma;
-char *p;
+ struct maccess ma;
+ char *p;
p = ad_dir(path);
if (!p)
- return -1;
+ return -1;
accessmode(p, &ma, curdir, NULL);
if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
/* --------------------- */
int file_access(struct path *path, int mode)
{
-struct maccess ma;
+ struct maccess ma;
accessmode(path->u_name, &ma, curdir, &path->st);
if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
dir->d_flags &= ~DIRF_CNID;
}
-/* ---------------------
+/* ---------------------
* is our cached offspring count valid?
-*/
+ */
-int diroffcnt(struct dir *dir, struct stat *st)
+static int diroffcnt(struct dir *dir, struct stat *st)
{
return st->st_ctime == dir->ctime;
}
-/* ---------------------
+/* ---------------------
* is our cached also for reenumerate id?
-*/
+ */
int dirreenumerate(struct dir *dir, struct stat *st)
{
/* --------------------- */
static int invisible_dots(const struct vol *vol, const char *name)
-{
- return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
+{
+ return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
}
-/* ------------------------------
+/* ------------------------------
(".", 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,
- char *buf, int *buflen )
+ struct dir *dir,
+ char *buf, size_t *buflen )
{
- struct maccess ma;
- struct adouble ad;
- char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
- int bit = 0, isad = 0;
+ struct maccess ma;
+ struct adouble ad;
+ char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
+ int bit = 0, isad = 0;
u_int32_t aint;
- u_int16_t ashort;
+ u_int16_t ashort;
int ret;
u_int32_t utf8 = 0;
cnid_t pdid;
struct stat *st = &s_path->st;
char *upath = s_path->u_name;
-
+
if ((bitmap & ((1 << DIRPBIT_ATTR) |
- (1 << DIRPBIT_CDATE) |
- (1 << DIRPBIT_MDATE) |
- (1 << DIRPBIT_BDATE) |
- (1 << DIRPBIT_FINFO)))) {
+ (1 << DIRPBIT_CDATE) |
+ (1 << DIRPBIT_MDATE) |
+ (1 << DIRPBIT_BDATE) |
+ (1 << DIRPBIT_FINFO)))) {
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) ) {
+ if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
isad = 1;
+ if (ad.ad_md->adf_flags & O_CREAT) {
+ /* We just created it */
+ ad_setname(&ad, s_path->m_name);
+ ad_setid( &ad,
+ s_path->st.st_dev,
+ s_path->st.st_ino,
+ dir->d_did,
+ dir->d_parent->d_did,
+ vol->v_stamp);
+ ad_flush( &ad);
+ }
}
}
-
+
if ( dir->d_did == DIRDID_ROOT) {
pdid = DIRDID_ROOT_PARENT;
} else if (dir->d_did == DIRDID_ROOT_PARENT) {
} else {
pdid = dir->d_parent->d_did;
}
-
+
data = buf;
while ( bitmap != 0 ) {
while (( bitmap & 1 ) == 0 ) {
ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
}
else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
- setdiroffcnt(dir, st, ret);
+ setdiroffcnt(dir, st, ret);
ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
}
ashort = htons( ashort );
/* Client has requested the ProDOS information block.
Just pass back the same basic block for all
directories. <shirsch@ibm.net> */
- case DIRPBIT_PDINFO :
+ case DIRPBIT_PDINFO :
if (afp_version >= 30) { /* UTF8 name */
utf8 = kTextEncodingUTF8;
if (dir->d_m_name) /* root of parent can have a null name */
aint = htonl(st->st_gid);
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
-
- aint = st->st_mode;
- aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
- memcpy( data, &aint, sizeof( aint ));
- data += sizeof( aint );
+
+ aint = st->st_mode;
+ aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
+ memcpy( data, &aint, sizeof( aint ));
+ data += sizeof( aint );
accessmode( upath, &ma, dir , st);
*data++ = ma.ma_group;
*data++ = ma.ma_owner;
break;
-
+
default :
if ( isad ) {
ad_close_metadata( &ad );
}
/* ----------------------------- */
-int afp_setdirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj;
-char *ibuf, *rbuf _U_;
-int ibuflen _U_, *rbuflen;
+int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
- struct vol *vol;
- struct dir *dir;
+ struct vol *vol;
+ struct dir *dir;
struct path *path;
- u_int16_t vid, bitmap;
+ u_int16_t vid, bitmap;
u_int32_t did;
- int rc;
+ int rc;
*rbuflen = 0;
ibuf += 2;
ibuf += sizeof( bitmap );
if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
- return get_afp_errno(AFPERR_NOOBJ);
+ return get_afp_errno(AFPERR_NOOBJ);
}
if ( *path->m_name != '\0' ) {
}
/*
- * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
+ * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
*
* assume path == '\0' eg. it's a directory in canonical form
-*/
+ */
struct path Cur_Path = {
0,
LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
return AFPERR_PARAM;
}
-
+
/* ------------------ */
-int setdirparams(const struct vol *vol,
+int setdirparams(struct vol *vol,
struct path *path, u_int16_t d_bitmap, char *buf )
{
- struct maccess ma;
- struct adouble ad;
+ struct maccess ma;
+ struct adouble ad;
struct utimbuf ut;
struct timeval tv;
char *upath;
struct dir *dir;
- int bit, isad = 1;
+ int bit, isad = 1;
int cdate, bdate;
int owner, group;
- u_int16_t ashort, bshort;
+ u_int16_t ashort, bshort, oshort;
int err = AFP_OK;
int change_mdate = 0;
int change_parent_mdate = 0;
int newdate = 0;
u_int16_t bitmap = d_bitmap;
u_char finder_buf[32];
- u_int32_t upriv;
- mode_t mpriv = 0;
+ u_int32_t upriv;
+ mode_t mpriv = 0;
u_int16_t upriv_bit = 0;
bit = 0;
memcpy( finder_buf, buf, 32 );
buf += 32;
break;
- case DIRPBIT_UID : /* What kind of loser mounts as root? */
+ case DIRPBIT_UID : /* What kind of loser mounts as root? */
change_parent_mdate = 1;
memcpy( &owner, buf, sizeof(owner));
buf += sizeof( owner );
bitmap = 0;
}
break;
- /* Ignore what the client thinks we should do to the
- ProDOS information block. Skip over the data and
- report nothing amiss. <shirsch@ibm.net> */
+ /* Ignore what the client thinks we should do to the
+ ProDOS information block. Skip over the data and
+ report nothing amiss. <shirsch@ibm.net> */
case DIRPBIT_PDINFO :
if (afp_version < 30) {
buf += 6;
bitmap = 0;
}
break;
- case DIRPBIT_UNIXPR :
- if (vol_unix_priv(vol)) {
+ case DIRPBIT_UNIXPR :
+ if (vol_unix_priv(vol)) {
memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
buf += sizeof( owner );
memcpy( &group, buf, sizeof( group ));
}
else {
/* do it later */
- upriv_bit = 1;
+ upriv_bit = 1;
}
break;
}
}
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open_metadata( upath, vol_noadouble(vol)|ADFLAGS_DIR, O_CREAT, &ad) < 0) {
+ if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
/*
* Check to see what we're trying to set. If it's anything
* but ACCESS, UID, or GID, give an error. If it's any of those
case DIRPBIT_ATTR :
if (isad) {
ad_getattr(&ad, &bshort);
- if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
- (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
- change_parent_mdate = 1;
+ oshort = bshort;
if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
} else {
bshort &= ~ashort;
}
+ if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
+ change_parent_mdate = 1;
ad_setattr(&ad, bshort);
}
break;
}
}
break;
- case DIRPBIT_UID : /* What kind of loser mounts as root? */
+ case DIRPBIT_UID : /* What kind of loser mounts as root? */
if ( (dir->d_did == DIRDID_ROOT) &&
- (setdeskowner( ntohl(owner), -1 ) < 0)) {
+ (setdeskowner( ntohl(owner), -1 ) < 0)) {
err = set_dir_errors(path, "setdeskowner", errno);
if (isad && err == AFPERR_PARAM) {
err = AFP_OK; /* ???*/
break;
case DIRPBIT_GID :
if (dir->d_did == DIRDID_ROOT)
- setdeskowner( -1, ntohl(group) );
+ setdeskowner( -1, ntohl(group) );
if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
err = set_dir_errors(path, "setdirowner", errno);
goto setdirparam_done;
goto setdirparam_done;
}
break;
- case DIRPBIT_UNIXPR :
- if (vol_unix_priv(vol)) {
+ case DIRPBIT_UNIXPR :
+ if (vol_unix_priv(vol)) {
if (dir->d_did == DIRDID_ROOT) {
if (!dir_rx_set(upriv)) {
/* we can't remove read and search for owner on volume root */
err = AFPERR_ACCESS;
goto setdirparam_done;
}
- setdeskowner( -1, ntohl(group) );
+ setdeskowner( -1, ntohl(group) );
setdeskmode( upriv );
}
if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
setdirparam_done:
if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
- newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
+ newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
}
if (newdate) {
- if (isad)
- ad_setdate(&ad, AD_DATE_MODIFY, newdate);
- ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
- utime(upath, &ut);
+ if (isad)
+ ad_setdate(&ad, AD_DATE_MODIFY, newdate);
+ ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
+ utime(upath, &ut);
}
if ( isad ) {
}
if (change_parent_mdate && dir->d_did != DIRDID_ROOT
- && gettimeofday(&tv, NULL) == 0) {
- if (!movecwd(vol, dir->d_parent)) {
- newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
- /* be careful with bitmap because now dir is null */
- bitmap = 1<<DIRPBIT_MDATE;
- setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
- /* should we reset curdir ?*/
- }
+ && gettimeofday(&tv, NULL) == 0) {
+ if (!movecwd(vol, dir->d_parent)) {
+ newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
+ /* be careful with bitmap because now dir is null */
+ bitmap = 1<<DIRPBIT_MDATE;
+ setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
+ /* should we reset curdir ?*/
+ }
}
return err;
}
-
-int afp_syncdir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj _U_;
-char *ibuf, *rbuf _U_;
-int ibuflen _U_, *rbuflen;
+int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
#ifdef HAVE_DIRFD
DIR *dp;
memcpy( &did, ibuf, sizeof( did ));
ibuf += sizeof( did );
- if (NULL == ( dir = dirlookup( vol, did )) ) {
- return afp_errno; /* was AFPERR_NOOBJ */
- }
- if (movecwd( vol, dir ) < 0 )
- return ( AFPERR_NOOBJ );
+ /*
+ * Here's the deal:
+ * if it's CNID 2 our only choice to meet the specs is call sync.
+ * For any other CNID just sync that dir. To my knowledge the
+ * intended use of FPSyncDir is to sync the volume so all we're
+ * ever going to see here is probably CNID 2. Anyway, we' prepared.
+ */
+
+ if ( ntohl(did) == 2 ) {
+ sync();
+ } else {
+ if (NULL == ( dir = dirlookup( vol, did )) ) {
+ return afp_errno; /* was AFPERR_NOOBJ */
+ }
+
+ if (movecwd( vol, dir ) < 0 )
+ return ( AFPERR_NOOBJ );
+
+ /*
+ * Assuming only OSens that have dirfd also may require fsyncing directories
+ * in order to flush metadata e.g. Linux.
+ */
-/*
- Assuming only OSens that have dirfd also may require fsyncing directories
- in order to flush metadata e.g. Linux.
-*/
-
#ifdef HAVE_DIRFD
- if (NULL == ( dp = opendir( "." )) ) {
- switch( errno ) {
- case ENOENT :
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- default :
- return( AFPERR_PARAM );
+ if (NULL == ( dp = opendir( "." )) ) {
+ switch( errno ) {
+ case ENOENT :
+ return( AFPERR_NOOBJ );
+ case EACCES :
+ return( AFPERR_ACCESS );
+ default :
+ return( AFPERR_PARAM );
+ }
}
- }
- LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
+ LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
- dfd = dirfd( dp );
- if ( fsync ( dfd ) < 0 )
- LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
- dir->d_u_name, strerror(errno) );
- closedir(dp); /* closes dfd too */
+ dfd = dirfd( dp );
+ if ( fsync ( dfd ) < 0 )
+ LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
+ dir->d_u_name, strerror(errno) );
+ closedir(dp); /* closes dfd too */
#endif
- if ( -1 == (dfd = open(vol->vfs->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
- switch( errno ) {
- case ENOENT:
- return( AFPERR_NOOBJ );
- case EACCES:
- return( AFPERR_ACCESS );
- default:
- return( AFPERR_PARAM );
- }
- }
+ if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
+ switch( errno ) {
+ case ENOENT:
+ return( AFPERR_NOOBJ );
+ case EACCES:
+ return( AFPERR_ACCESS );
+ default:
+ return( AFPERR_PARAM );
+ }
+ }
- LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
- vol->vfs->ad_path(".", ADFLAGS_DIR) );
-
- if ( fsync(dfd) < 0 )
- LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
- vol->vfs->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
- close(dfd);
+ LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
+ vol->ad_path(".", ADFLAGS_DIR) );
+
+ if ( fsync(dfd) < 0 )
+ LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
+ vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
+ close(dfd);
+ }
return ( AFP_OK );
}
-int afp_createdir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj;
-char *ibuf, *rbuf;
-int ibuflen _U_, *rbuflen;
+int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- struct adouble ad;
- struct vol *vol;
- struct dir *dir;
- char *upath;
+ struct adouble ad;
+ struct vol *vol;
+ struct dir *dir;
+ char *upath;
struct path *s_path;
- u_int32_t did;
- u_int16_t vid;
+ u_int32_t did;
+ u_int16_t vid;
int err;
-
+
*rbuflen = 0;
ibuf += 2;
}
/* for concurrent access we need to be sure we are not in the
* folder we want to create...
- */
+ */
movecwd(vol, dir);
-
+
if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
return get_afp_errno(AFPERR_PARAM);
}
}
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open_metadata( ".", vol_noadouble(vol)|ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
+ if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
if (vol_noadouble(vol))
goto createdir_done;
return( AFPERR_ACCESS );
* newname new mac name
* newparent curdir
*
-*/
-int renamedir(vol, src, dst, dir, newparent, newname)
-const struct vol *vol;
-char *src, *dst, *newname;
-struct dir *dir, *newparent;
+ */
+int renamedir(const struct vol *vol, char *src, char *dst,
+ struct dir *dir,
+ struct dir *newparent,
+ char *newname)
{
- struct adouble ad;
- struct dir *parent;
+ struct adouble ad;
+ struct dir *parent;
char *buf;
- int len, err;
-
+ int len, err;
+
/* existence check moved to afp_moveandrename */
if ( unix_rename( src, dst ) < 0 ) {
switch ( errno ) {
}
}
- vol->vfs->rf_renamedir(vol, src, dst);
+ vol->vfs->vfs_renamedir(vol, src, dst);
len = strlen( newname );
/* rename() succeeded so we need to update our tree even if we can't open
* metadata
- */
-
+ */
+
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
strcpy( dir->d_m_name, newname );
if (newname == dst) {
- free(dir->d_u_name);
- dir->d_u_name = dir->d_m_name;
+ free(dir->d_u_name);
+ dir->d_u_name = dir->d_m_name;
}
else {
if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
}
if (dir->d_m_name_ucs2)
- free(dir->d_m_name_ucs2);
+ free(dir->d_m_name_ucs2);
dir->d_m_name_ucs2 = NULL;
- if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, strlen(dir->d_m_name), (char**)&dir->d_m_name_ucs2))
+ if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, -1, (char**)&dir->d_m_name_ucs2))
dir->d_m_name_ucs2 = NULL;
if (( parent = dir->d_parent ) == NULL ) {
}
/* delete an empty directory */
-int deletecurdir( vol)
-const struct vol *vol;
+int deletecurdir(struct vol *vol)
{
struct dirent *de;
struct stat st;
- struct dir *fdir;
+ struct dir *fdir;
DIR *dp;
- struct adouble ad;
- u_int16_t ashort;
+ struct adouble ad;
+ u_int16_t ashort;
int err;
if ( curdir->d_parent == NULL ) {
fdir = curdir;
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ /* we never want to create a resource fork here, we are going to delete it */
if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
ad_getattr(&ad, &ashort);
return AFPERR_OLOCK;
}
}
- err = vol->vfs->rf_deletecurdir(vol);
+ err = vol->vfs->vfs_deletecurdir(vol);
if (err) {
return err;
}
/* bail if it's not a symlink */
if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
- closedir(dp);
+ closedir(dp);
return AFPERR_DIRNEMPT;
}
if ((err = netatalk_unlink(de->d_name))) {
- closedir(dp);
- return err;
+ closedir(dp);
+ return err;
}
}
}
goto delete_done;
}
- if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
+ err = netatalk_rmdir_all_errors(fdir->d_u_name);
+ if ( err == AFP_OK || err == AFPERR_NOOBJ) {
dirchildremove(curdir, fdir);
cnid_delete(vol->v_cdb, fdir->d_did);
dir_remove( vol, fdir );
- err = AFP_OK;
}
delete_done:
if (dp) {
/* inode is used as key for cnid.
* Close the descriptor only after cnid_delete
- * has been called.
- */
+ * has been called.
+ */
closedir(dp);
}
return err;
}
-int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj;
-char *ibuf, *rbuf;
-int ibuflen _U_, *rbuflen;
+int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- struct passwd *pw;
- struct group *gr;
- char *name;
+ struct passwd *pw;
+ struct group *gr;
+ char *name;
u_int32_t id;
- int len, sfunc;
+ int len, sfunc;
int utf8 = 0;
- uuidtype_t type;
ibuf++;
sfunc = (unsigned char) *ibuf++;
utf8 = 1;
}
- switch ( sfunc ) {
- case 1 :
- case 3 :/* unicode */
- memcpy( &id, ibuf, sizeof( id ));
- id = ntohl(id);
- if ( id != 0 ) {
+ switch ( sfunc ) {
+ case 1 :
+ case 3 :/* unicode */
+ memcpy( &id, ibuf, sizeof( id ));
+ id = ntohl(id);
+ if ( id != 0 ) {
if (( pw = getpwuid( id )) == NULL ) {
return( AFPERR_NOITEM );
}
- len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
- pw->pw_name, strlen(pw->pw_name), &name);
- } else {
- len = 0;
- name = NULL;
- }
- break;
- case 2 :
- case 4 : /* unicode */
- memcpy( &id, ibuf, sizeof( id ));
- id = ntohl(id);
- if ( id != 0 ) {
+ len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
+ pw->pw_name, -1, &name);
+ } else {
+ len = 0;
+ name = NULL;
+ }
+ break;
+ case 2 :
+ case 4 : /* unicode */
+ memcpy( &id, ibuf, sizeof( id ));
+ id = ntohl(id);
+ if ( id != 0 ) {
if (NULL == ( gr = (struct group *)getgrgid( id ))) {
return( AFPERR_NOITEM );
}
- len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
- gr->gr_name, strlen(gr->gr_name), &name);
- } else {
- len = 0;
- name = NULL;
- }
- break;
+ len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
+ gr->gr_name, -1, &name);
+ } else {
+ len = 0;
+ name = NULL;
+ }
+ break;
#ifdef HAVE_NFSv4_ACLS
case 5 : /* UUID -> username */
case 6 : /* UUID -> groupname */
- if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
- return AFPERR_PARAM;
- LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
- len = getnamefromuuid( ibuf, &name, &type);
- if (len != 0) /* its a error code, not len */
- return AFPERR_NOITEM;
- if (type == UUID_USER) {
- if (( pw = getpwnam( name )) == NULL )
- return( AFPERR_NOITEM );
- LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
- id = htonl(UUID_USER);
- memcpy( rbuf, &id, sizeof( id ));
- id = htonl( pw->pw_uid);
- rbuf += sizeof( id );
- memcpy( rbuf, &id, sizeof( id ));
- rbuf += sizeof( id );
- *rbuflen = 2 * sizeof( id );
- } else { /* type == UUID_GROUP */
+ if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
+ return AFPERR_PARAM;
+ LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
+ uuidtype_t type;
+ len = getnamefromuuid( ibuf, &name, &type);
+ if (len != 0) /* its a error code, not len */
+ return AFPERR_NOITEM;
+ if (type == UUID_USER) {
+ if (( pw = getpwnam( name )) == NULL )
+ return( AFPERR_NOITEM );
+ LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
+ id = htonl(UUID_USER);
+ memcpy( rbuf, &id, sizeof( id ));
+ id = htonl( pw->pw_uid);
+ rbuf += sizeof( id );
+ memcpy( rbuf, &id, sizeof( id ));
+ rbuf += sizeof( id );
+ *rbuflen = 2 * sizeof( id );
+ } else { /* type == UUID_GROUP */
if (( gr = getgrnam( name )) == NULL )
return( AFPERR_NOITEM );
- LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
- id = htonl(UUID_GROUP);
- memcpy( rbuf, &id, sizeof( id ));
- rbuf += sizeof( id );
- id = htonl( gr->gr_gid);
- memcpy( rbuf, &id, sizeof( id ));
- rbuf += sizeof( id );
- *rbuflen = 2 * sizeof( id );
- }
- break;
-#endif
- default :
- return( AFPERR_PARAM );
+ LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
+ id = htonl(UUID_GROUP);
+ memcpy( rbuf, &id, sizeof( id ));
+ rbuf += sizeof( id );
+ id = htonl( gr->gr_gid);
+ memcpy( rbuf, &id, sizeof( id ));
+ rbuf += sizeof( id );
+ *rbuflen = 2 * sizeof( id );
}
+ break;
+#endif
+ default :
+ return( AFPERR_PARAM );
+ }
+
+ if (name)
+ len = strlen( name );
- if (name)
- len = strlen( name );
-
if (utf8) {
u_int16_t tp = htons(len);
memcpy(rbuf, &tp, sizeof(tp));
}
*rbuflen += len;
if (name)
- free(name);
+ free(name);
return( AFP_OK );
}
-int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj _U_;
-char *ibuf, *rbuf;
-int ibuflen _U_, *rbuflen;
+int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- struct passwd *pw;
- struct group *gr;
+ struct passwd *pw;
+ struct group *gr;
int len, sfunc;
u_int32_t id;
u_int16_t ulen;
*rbuflen = 0;
LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
switch ( sfunc ) {
- case 1 :
+ case 1 :
case 2 : /* unicode */
if (afp_version < 30) {
return( AFPERR_PARAM );
memcpy(&ulen, ibuf, sizeof(ulen));
len = ntohs(ulen);
ibuf += 2;
- LOG(log_debug, logtype_afpd, "afp_mapname: alive");
+ LOG(log_debug, logtype_afpd, "afp_mapname: alive");
break;
case 3 :
case 4 :
ibuf[ len ] = '\0';
if ( len == 0 )
- return AFPERR_PARAM;
+ return AFPERR_PARAM;
else {
switch ( sfunc ) {
case 1 : /* unicode */
return( AFPERR_NOITEM );
}
id = pw->pw_uid;
- id = htonl(id);
- memcpy( rbuf, &id, sizeof( id ));
- *rbuflen = sizeof( id );
+ id = htonl(id);
+ memcpy( rbuf, &id, sizeof( id ));
+ *rbuflen = sizeof( id );
break;
case 2 : /* unicode */
case 4 :
- LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
+ LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
return( AFPERR_NOITEM );
}
id = gr->gr_gid;
- LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
- id = htonl(id);
- memcpy( rbuf, &id, sizeof( id ));
- *rbuflen = sizeof( id );
- break;
+ LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
+ id = htonl(id);
+ memcpy( rbuf, &id, sizeof( id ));
+ *rbuflen = sizeof( id );
+ break;
#ifdef HAVE_NFSv4_ACLS
- case 5 : /* username -> UUID */
- LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
- if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
- return AFPERR_NOITEM;
- *rbuflen = UUID_BINSIZE;
- break;
- case 6 : /* groupname -> UUID */
- LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
- if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
- return AFPERR_NOITEM;
- *rbuflen = UUID_BINSIZE;
- break;
+ case 5 : /* username -> UUID */
+ LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
+ if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
+ return AFPERR_NOITEM;
+ *rbuflen = UUID_BINSIZE;
+ break;
+ case 6 : /* groupname -> UUID */
+ LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
+ if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
+ return AFPERR_NOITEM;
+ *rbuflen = UUID_BINSIZE;
+ break;
#endif
}
}
}
/* ------------------------------------
- variable DID support
+ variable DID support
*/
-int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj _U_;
-char *ibuf _U_, *rbuf _U_;
-int ibuflen _U_, *rbuflen;
+int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
#if 0
struct vol *vol;
return AFP_OK;
}
-/* did creation gets done automatically
+/* did creation gets done automatically
* there's a pb again with case but move it to cname
-*/
-int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj _U_;
-char *ibuf, *rbuf;
-int ibuflen _U_, *rbuflen;
+ */
+int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- struct vol *vol;
- struct dir *parentdir;
- struct path *path;
- u_int32_t did;
- u_int16_t vid;
+ struct vol *vol;
+ struct dir *parentdir;
+ struct path *path;
+ u_int32_t did;
+ u_int16_t vid;
*rbuflen = 0;
ibuf += 2;
}
if ( *path->m_name != '\0' ) {
- return path_error(path, AFPERR_NOOBJ);
+ return path_error(path, AFPERR_NOOBJ);
}
if ( !path->st_valid && of_stat(path ) < 0 ) {