2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
11 #include <sys/syslog.h>
12 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <netatalk/endian.h>
16 #include <atalk/adouble.h>
17 #include <atalk/afp.h>
18 #include <atalk/util.h>
19 #include <atalk/cnid.h>
29 #include "directory.h"
37 int afp_getfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
40 int ibuflen, *rbuflen;
48 u_int16_t fbitmap, dbitmap, vid;
53 memcpy( &vid, ibuf, sizeof( vid ));
54 ibuf += sizeof( vid );
55 if (( vol = getvolbyvid( vid )) == NULL ) {
56 return( AFPERR_PARAM );
59 memcpy( &did, ibuf, sizeof( did ));
60 ibuf += sizeof( did );
62 if (( dir = dirsearch( vol, did )) == NULL ) {
63 return( AFPERR_NOOBJ );
66 memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
67 fbitmap = ntohs( fbitmap );
68 ibuf += sizeof( fbitmap );
69 memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
70 dbitmap = ntohs( dbitmap );
71 ibuf += sizeof( dbitmap );
73 if (( path = cname( vol, dir, &ibuf )) == NULL) {
74 return( AFPERR_NOOBJ );
77 if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
78 return( AFPERR_NOOBJ );
82 if (S_ISDIR(st.st_mode)) {
83 if (dbitmap && ( ret = getdirparams(vol, dbitmap, ".", curdir,
84 &st, rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
87 /* this is a directory */
88 *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISDIR;
90 if (fbitmap && ( ret = getfilparams(vol, fbitmap, path, curdir, &st,
91 rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
95 *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISFILE;
97 *rbuflen = buflen + 3 * sizeof( u_int16_t );
98 fbitmap = htons( fbitmap );
99 memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
100 rbuf += sizeof( fbitmap );
101 dbitmap = htons( dbitmap );
102 memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
103 rbuf += sizeof( dbitmap ) + sizeof( u_char );
109 int afp_setfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
112 int ibuflen, *rbuflen;
118 u_int16_t vid, bitmap;
123 memcpy( &vid, ibuf, sizeof(vid));
124 ibuf += sizeof( vid );
126 if (( vol = getvolbyvid( vid )) == NULL ) {
127 return( AFPERR_PARAM );
130 if (vol->v_flags & AFPVOL_RO)
133 memcpy( &did, ibuf, sizeof( did));
134 ibuf += sizeof( did);
136 if (( dir = dirsearch( vol, did )) == NULL ) {
137 return( AFPERR_NOOBJ );
140 memcpy( &bitmap, ibuf, sizeof( bitmap ));
141 bitmap = ntohs( bitmap );
142 ibuf += sizeof( bitmap );
144 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
145 return( AFPERR_NOOBJ );
148 if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
149 return( AFPERR_NOOBJ );
153 * If ibuf is odd, make it even.
155 if ((u_long)ibuf & 1 ) {
159 if (S_ISDIR(st.st_mode)) {
160 rc = setdirparams(vol, path, bitmap, ibuf );
162 rc = setfilparams(vol, path, bitmap, ibuf );
164 if ( rc == AFP_OK ) {
165 setvoltime(obj, vol );
170 int afp_rename(obj, ibuf, ibuflen, rbuf, rbuflen )
173 int ibuflen, *rbuflen;
178 struct dir *dir, *odir = NULL;
179 char *path, *buf, *upath, *newpath;
184 #if AD_VERSION > AD_VERSION1
191 memcpy( &vid, ibuf, sizeof( vid ));
192 ibuf += sizeof( vid );
193 if (( vol = getvolbyvid( vid )) == NULL ) {
194 return( AFPERR_PARAM );
197 if (vol->v_flags & AFPVOL_RO)
200 memcpy( &did, ibuf, sizeof( did ));
201 ibuf += sizeof( did );
202 if (( dir = dirsearch( vol, did )) == NULL ) {
203 return( AFPERR_NOOBJ );
206 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
207 return( AFPERR_NOOBJ );
210 /* another place where we know about the path type */
211 if ( *ibuf++ != 2 ) {
212 return( AFPERR_PARAM );
214 plen = (unsigned char) *ibuf++;
215 *( ibuf + plen ) = '\0';
217 if ( *path == '\0' ) {
218 if ( curdir->d_parent == NULL ) { /* root directory */
219 return( AFPERR_NORENAME );
222 path = curdir->d_name;
223 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
224 return( AFPERR_NOOBJ );
229 if ( strcasecmp( path, ibuf ) == 0 ) {
234 /* if a curdir/newname ofork exists, return busy */
235 if (of_findname(vol, curdir, ibuf))
238 /* source == destination. just say okay. */
239 if (strcmp(path, ibuf) == 0)
242 /* check for illegal characters */
243 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
244 strpbrk(ibuf, MSWINDOWS_BADCHARS))
247 newpath = obj->oldtmp;
248 strcpy( newpath, mtoupath(vol, ibuf ));
250 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(newpath, '/'))
253 if (!validupath(vol, newpath))
256 /* the strdiacasecmp deals with case-insensitive, case preserving
258 if (stat( newpath, &st ) == 0 && strdiacasecmp(path, ibuf))
259 return( AFPERR_EXIST );
261 upath = mtoupath(vol, path);
263 #if AD_VERSION > AD_VERSION1
264 id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
267 if ( rename( upath, newpath ) < 0 ) {
270 return( AFPERR_NOOBJ );
272 return( AFPERR_ACCESS );
274 return( AFPERR_PARAM );
278 #if AD_VERSION > AD_VERSION1
279 if (stat(newpath, &st) < 0) /* this shouldn't fail */
281 cnid_update(vol->v_db, id, &st, curdir->d_did, newpath, strlen(newpath));
285 newadpath = obj->newtmp;
286 strcpy( newadpath, ad_path( newpath, 0 ));
287 if ( rename( ad_path( upath, 0 ), newadpath ) < 0 ) {
288 if ( errno == ENOENT ) { /* no adouble header file */
289 if (( unlink( newadpath ) < 0 ) && ( errno != ENOENT )) {
290 return( AFPERR_PARAM );
294 return( AFPERR_PARAM );
297 memset(&ad, 0, sizeof(ad));
298 if ( ad_open( newpath, ADFLAGS_HF, O_RDWR|O_CREAT, 0666,
300 return( AFPERR_PARAM );
305 memset(&ad, 0, sizeof(ad));
306 if ( ad_open( newpath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
307 O_RDWR|O_CREAT, 0666, &ad) < 0 ) {
308 if (!((errno == ENOENT) && vol_noadouble(vol)))
309 return( AFPERR_PARAM );
312 if ((buf = realloc( odir->d_name, plen + 1 )) == NULL ) {
313 syslog( LOG_ERR, "afp_rename: realloc: %m" );
315 ad_flush(&ad, ADFLAGS_HF); /* in case of create */
316 ad_close(&ad, ADFLAGS_HF);
321 strcpy( odir->d_name, ibuf );
326 ad_setentrylen( &ad, ADEID_NAME, plen );
327 memcpy( ad_entry( &ad, ADEID_NAME ), ibuf, plen );
328 ad_flush( &ad, ADFLAGS_HF );
329 ad_close( &ad, ADFLAGS_HF );
332 setvoltime(obj, vol );
334 /* if it's still open, rename the ofork as well. */
335 if (of_rename(vol, curdir, path, curdir, ibuf) < 0)
342 int afp_delete(obj, ibuf, ibuflen, rbuf, rbuflen )
345 int ibuflen, *rbuflen;
356 memcpy( &vid, ibuf, sizeof( vid ));
357 ibuf += sizeof( vid );
358 if (( vol = getvolbyvid( vid )) == NULL ) {
359 return( AFPERR_PARAM );
362 if (vol->v_flags & AFPVOL_RO)
365 memcpy( &did, ibuf, sizeof( did ));
366 ibuf += sizeof( int );
367 if (( dir = dirsearch( vol, did )) == NULL ) {
368 return( AFPERR_NOOBJ );
371 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
372 return( AFPERR_NOOBJ );
375 if ( *path == '\0' ) {
376 rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ);
377 } else if (of_findname(vol, curdir, path)) {
379 } else if ((rc = deletefile( upath = mtoupath(vol, path ))) == AFP_OK) {
380 #if AD_VERSION > AD_VERSION1 /* get rid of entry */
381 cnid_t id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
382 cnid_delete(vol->v_db, id);
385 if ( rc == AFP_OK ) {
386 setvoltime(obj, vol );
391 char *ctoupath( vol, dir, name )
392 const struct vol *vol;
397 static char path[ MAXPATHLEN + 1];
401 p = path + sizeof( path ) - 1;
403 u = mtoupath(vol, name );
406 strncpy( p, u, len );
407 for ( d = dir; d->d_parent; d = d->d_parent ) {
409 u = mtoupath(vol, d->d_name );
412 strncpy( p, u, len );
415 len = strlen( vol->v_path );
417 strncpy( p, vol->v_path, len );
423 int afp_moveandrename(obj, ibuf, ibuflen, rbuf, rbuflen )
426 int ibuflen, *rbuflen;
429 struct dir *sdir, *ddir, *odir = NULL;
431 char *oldname, *newname;
432 char *path, *p, *upath;
436 #if AD_VERSION > AD_VERSION1
449 memcpy( &vid, ibuf, sizeof( vid ));
450 ibuf += sizeof( vid );
451 if (( vol = getvolbyvid( vid )) == NULL ) {
452 return( AFPERR_PARAM );
455 if (vol->v_flags & AFPVOL_RO)
458 /* source did followed by dest did */
459 memcpy( &did, ibuf, sizeof( did ));
460 ibuf += sizeof( int );
461 if (( sdir = dirsearch( vol, did )) == NULL ) {
462 return( AFPERR_PARAM );
465 memcpy( &did, ibuf, sizeof( did ));
466 ibuf += sizeof( int );
468 /* source pathname */
469 if (( path = cname( vol, sdir, &ibuf )) == NULL ) {
470 return( AFPERR_NOOBJ );
474 newname = obj->newtmp;
475 oldname = obj->oldtmp;
476 if ( *path != '\0' ) {
477 /* not a directory */
478 strcpy(newname, path);
479 strcpy(oldname, path); /* an extra copy for of_rename */
480 #if AD_VERSION > AD_VERSION1
481 p = mtoupath(vol, path);
482 id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p));
484 p = ctoupath( vol, sdir, newname );
487 strcpy( newname, odir->d_name );
488 strcpy(oldname, odir->d_name);
489 p = ctoupath( vol, odir->d_parent, newname );
490 #if AD_VERSION > AD_VERSION1
491 id = curdir->d_did; /* we already have the CNID */
495 * p now points to the full pathname of the source fs object.
498 /* get the destination directory */
499 if (( ddir = dirsearch( vol, did )) == NULL ) {
500 return( AFPERR_PARAM );
502 if (( path = cname( vol, ddir, &ibuf )) == NULL ) {
503 return( AFPERR_NOOBJ );
505 if ( *path != '\0' ) {
506 return( AFPERR_BADTYPE );
509 /* one more place where we know about path type */
510 if ( *ibuf++ != 2 ) {
511 return( AFPERR_PARAM );
514 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
515 strncpy( newname, ibuf, plen );
516 newname[ plen ] = '\0';
519 /* check for illegal characters */
520 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
521 strpbrk(newname, MSWINDOWS_BADCHARS))
524 upath = mtoupath(vol, newname);
526 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
529 if (!validupath(vol, upath))
532 /* source == destination. we just silently accept this. */
533 if (curdir == sdir) {
534 if (strcmp(oldname, newname) == 0)
537 /* deal with case insensitive, case-preserving filesystems. */
538 if ((stat(upath, &st) == 0) && strdiacasecmp(oldname, newname))
541 } else if (stat(upath, &st ) == 0)
542 return( AFPERR_EXIST );
545 if (of_findname(vol, curdir, newname)) {
547 } else if ((rc = renamefile( p, upath, newname,
548 vol_noadouble(vol) )) == AFP_OK) {
549 /* if it's still open, rename the ofork as well. */
550 rc = of_rename(vol, sdir, oldname, curdir, newname);
553 rc = renamedir(p, upath, odir, curdir, newname, vol_noadouble(vol));
556 strcpy (adpath, "./.AppleDouble/");
557 strcat (adpath, newname);
558 if (( dir = dirsearch( vol, did )) == NULL ) {
559 syslog (LOG_ERR, "afp_moveandrename: Unable to get directory info.");
560 return( AFPERR_NOOBJ );
563 if (stat(".", &sb) < 0) {
564 syslog (LOG_ERR, "afp_moveandrename: Error checking directory \"%s\": %m", dir->d_name);
569 if ( uid != sb.st_uid )
572 if (lchown(newname, sb.st_uid, sb.st_gid) < 0)
574 syslog (LOG_ERR, "afp_moveandrename: Error changing owner/gid of %s: %m", p);
577 if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
579 syslog (LOG_ERR, "afp_moveandrename: Error changing AppleDouble owner/gid %s: %m", adpath);
584 syslog (LOG_DEBUG, "No ownership change necessary.");
586 seteuid(uid); /* Restore process ownership to normal */
589 if ( rc == AFP_OK ) {
590 #if AD_VERSION > AD_VERSION1
591 /* renaming may have moved the file/dir across a filesystem */
592 if (stat(upath, &st) < 0)
595 /* fix up the catalog entry */
596 cnid_update(vol->v_db, id, &st, curdir->d_did, upath, strlen(newname));
598 setvoltime(obj, vol );