/*
- * $Id: directory.c,v 1.28 2002-03-24 01:23:40 sibaz Exp $
+ * $Id: directory.c,v 1.34 2002-06-17 18:23:02 didg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
return NULL;
}
+/* -----------------------------------------
+ * if did is not in the cache resolve it with cnid
+ *
+ */
+struct dir *
+ dirlookup( vol, did )
+ const struct vol *vol;
+u_int32_t did;
+{
+#ifdef CNID_DB
+ struct dir *ret;
+ char *upath;
+ u_int32_t id;
+ static char path[MAXPATHLEN + 1];
+ int len;
+ int pathlen;
+ char *ptr;
+ static char buffer[12 + MAXPATHLEN + 1];
+ int buflen = 12 + MAXPATHLEN + 1;
+
+ ret = dirsearch(vol, did);
+ if (ret != NULL)
+ return ret;
+
+ id = did;
+ if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL) {
+ return NULL;
+ }
+ ptr = path + MAXPATHLEN;
+ len = strlen(upath);
+ pathlen = len; /* no 0 in the last part */
+ len++;
+ strcpy(ptr - len, upath);
+ ptr -= len;
+ while (1) {
+ ret = dirsearch(vol,id);
+ if (ret != NULL) {
+ break;
+ }
+ if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL)
+ return NULL;
+ len = strlen(upath) + 1;
+ pathlen += len;
+ if (pathlen > 255)
+ return NULL;
+ strcpy(ptr - len, upath);
+ ptr -= len;
+ }
+ /* fill the cache */
+ ptr--;
+ *ptr = (unsigned char)pathlen;
+ ptr--;
+ *ptr = 2;
+ /* cname is not efficient */
+ if (cname( vol, ret, &ptr ) == NULL )
+ return NULL;
+#endif
+ return dirsearch(vol, did);
+}
+/* --------------------------- */
/* rotate the tree to the left */
static void dir_leftrotate(vol, dir)
struct vol *vol;
#endif /* ! REMOVE_NODES */
}
+/* ---------------------------------------
+ * remove the node and its childs from the tree
+ *
+ * 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
+ * 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;
+{
+ if (curdir == dir) {
+ /* v_root can't be deleted */
+ if (movecwd(vol, vol->v_root) < 0)
+ printf("Yuup cant change dir to v_root\n");
+ }
+ /* FIXME */
+ dirchildremove(dir->d_parent, dir);
+ dir_remove( vol, dir );
+}
+/* ------------------------------------ */
static struct dir *dir_insert(vol, dir)
const struct vol *vol;
struct dir *dir;
struct dir *cdir;
static char path[ MAXPATHLEN + 1];
char *data, *p;
+ char *u;
int extend = 0;
int len;
-
+ int olen = 0;
+
data = *cpath;
if ( *data++ != 2 ) { /* path type */
return( NULL );
len = (unsigned char) *data++;
*cpath += len + 2;
*path = '\0';
+ u = NULL;
for ( ;; ) {
if ( len == 0 ) {
if ( !extend && movecwd( vol, dir ) < 0 ) {
- return( NULL );
+ /* it's tricky:
+ movecwd failed so dir is 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.
+
+ */
+ if ( dir->d_did == DIRDID_ROOT_PARENT)
+ return NULL;
+ cdir = dir->d_parent;
+ 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( path );
}
data++;
len--;
}
+ u = NULL;
while ( *data == '\0' && len > 0 ) {
if ( dir->d_parent == NULL ) {
/* would this be faster with strlen + strncpy? */
p = path;
+ if (len > 0) {
+ u = data;
+ olen = len;
+ }
while ( *data != '\0' && len > 0 ) {
*p++ = *data++;
len--;
}
if ( cdir == NULL ) {
++extend;
+ /* if dir == curdir it always succeed,
+ even if curdir is deleted.
+ it's not a pb because it will failed in extenddir
+ */
if ( movecwd( vol, dir ) < 0 ) {
+ /* dir is not valid anymore
+ we delete dir from the cache and abort.
+ */
+ dir_invalidate(vol, dir);
return( NULL );
}
cdir = extenddir( vol, dir, path );
}
} else {
- dir = cdir;
+ dir = cdir;
*path = '\0';
}
}
ashort = htons(ATTRBIT_INVISIBLE);
} else
ashort = 0;
+ ashort |= htons(ATTRBIT_SHARED);
memcpy( data, &ashort, sizeof( ashort ));
data += sizeof( ashort );
break;
switch( errno ) {
case EACCES:
return( AFPERR_ACCESS );
- case EEXIST:
+ case EEXIST: /* FIXME this on is impossible? */
return( AFPERR_EXIST );
default:
return( AFPERR_NOOBJ );
}
}
-
+ /* FIXME check done elswhere? cname was able to move curdir to it! */
+ if (*path == '\0')
+ return AFPERR_EXIST;
upath = mtoupath(vol, path);
-
- /* check for illegal bits in the unix filename */
- if (!wincheck(vol, upath))
- return AFPERR_PARAM;
-
- if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
- return AFPERR_PARAM;
-
- if (!validupath(vol, upath))
- return AFPERR_EXIST;
-
- /* check for vetoed filenames */
- if (veto_file(vol->v_veto, upath))
- return AFPERR_EXIST;
+ {
+ int ret;
+ if (0 != (ret = check_name(vol, upath))) {
+ return ret;
+ }
+ }
#ifdef FORCE_UIDGID
save_uidgid ( &uidgid );
struct stat st;
struct dir *fdir;
DIR *dp;
+ struct adouble ad;
+ u_int16_t ashort;
#ifdef FORCE_UIDGID
uidgidset *uidgid;
set_uidgid ( vol );
#endif /* FORCE_UIDGID */
+ memset(&ad, 0, sizeof(ad));
+ if ( ad_open( ".", ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
+ DIRBITS | 0777, &ad) == 0 ) {
+
+ ad_getattr(&ad, &ashort);
+ ad_close( &ad, ADFLAGS_HF );
+ if ((ashort & htons(ATTRBIT_NODELETE))) {
+#ifdef FORCE_UIDGID
+ restore_uidgid ( &uidgid );
+#endif /* FORCE_UIDGID */
+ return AFPERR_OLOCK;
+ }
+ }
+
/* delete stray .AppleDouble files. this happens to get .Parent files
as well. */
if ((dp = opendir(".AppleDouble"))) {