2 * $Id: file.c,v 1.22 2001-06-20 18:33:04 rufustfirefly Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #endif /* HAVE_FCNTL_H */
26 #include <sys/syslog.h>
27 #include <sys/types.h>
29 #include <sys/param.h>
32 #include <netatalk/endian.h>
33 #include <atalk/adouble.h>
34 #include <atalk/afp.h>
35 #include <atalk/util.h>
36 #include <atalk/cnid.h>
38 #include "directory.h"
46 /* check for mtab DID code */
48 #include "parse_mtab.h"
53 #endif /* FORCE_UIDGID */
55 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
56 * field bytes subfield bytes
59 * ioFlFndrInfo 16 -> type 4 type field
60 * creator 4 creator field
61 * flags 2 finder flags:
63 * location 4 location in window
64 * folder 2 window that contains file
66 * ioFlXFndrInfo 16 -> iconID 2 icon id
68 * script 1 script system
70 * commentID 2 comment id
71 * putawayID 4 home directory id
74 const u_char ufinderi[] = {
75 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
76 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0
81 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
91 struct stat hst, lst, *lstp;
92 #else /* USE_LASTDID */
94 #endif /* USE_LASTDID */
95 struct adouble ad, *adp;
98 char *data, *nameoff = NULL, *upath;
99 int bit = 0, isad = 1, aint;
101 u_char achar, fdType[4];
104 syslog(LOG_INFO, "begin getfilparams:");
107 upath = mtoupath(vol, path);
108 if ((of = of_findname(vol, curdir, path))) {
111 memset(&ad, 0, sizeof(ad));
115 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
117 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
118 syslog( LOG_ERR, "getfilparams fstat: %m" );
122 while ( bitmap != 0 ) {
123 while (( bitmap & 1 ) == 0 ) {
131 ad_getattr(adp, &ashort);
132 } else if (*upath == '.') {
133 ashort = htons(ATTRBIT_INVISIBLE);
136 memcpy(data, &ashort, sizeof( ashort ));
137 data += sizeof( u_short );
141 memcpy(data, &dir->d_did, sizeof( int ));
142 data += sizeof( int );
146 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
147 aint = AD_DATE_FROM_UNIX(st->st_mtime);
148 memcpy(data, &aint, sizeof( aint ));
149 data += sizeof( aint );
153 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
154 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
155 (hst.st_mtime < st->st_mtime)) {
156 aint = AD_DATE_FROM_UNIX(st->st_mtime);
159 aint = AD_DATE_FROM_UNIX(st->st_mtime);
161 memcpy(data, &aint, sizeof( int ));
162 data += sizeof( int );
166 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
167 aint = AD_DATE_START;
168 memcpy(data, &aint, sizeof( int ));
169 data += sizeof( int );
174 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
176 memcpy(data, ufinderi, 32);
177 if (*upath == '.') { /* make it invisible */
178 ashort = htons(FINDERINFO_INVISIBLE);
179 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
183 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
184 ufinderi, 8 ) == 0)) &&
185 (em = getextmap( path ))) {
186 memcpy(data, em->em_type, sizeof( em->em_type ));
187 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
194 data += sizeof( u_int16_t );
198 memset(data, 0, sizeof(u_int16_t));
199 data += sizeof( u_int16_t );
203 #if AD_VERSION > AD_VERSION1
204 /* use the CNID database if we're using AD v2 */
206 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
210 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
211 strlen(upath), aint))) {
212 #endif /* AD_VERSION > AD_VERSION1 */
214 * What a fucking mess. First thing: DID and FNUMs are
215 * in the same space for purposes of enumerate (and several
216 * other wierd places). While we consider this Apple's bug,
217 * this is the work-around: In order to maintain constant and
218 * unique DIDs and FNUMs, we monotonically generate the DIDs
219 * during the session, and derive the FNUMs from the filesystem.
220 * Since the DIDs are small, we insure that the FNUMs are fairly
221 * large by setting thier high bits to the device number.
223 * AFS already does something very similar to this for the
224 * inode number, so we don't repeat the procedure.
227 * due to complaints over did's being non-persistent,
228 * here's the current hack to provide semi-persistent
230 * 1) we reserve the first bit for file ids.
231 * 2) the next 7 bits are for the device.
232 * 3) the remaining 24 bits are for the inode.
234 * both the inode and device information are actually hashes
235 * that are then truncated to the requisite bit length.
237 * it should be okay to use lstat to deal with symlinks.
240 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
241 #else /* USE_LASTDID */
242 lstp = lstat(upath, &lst) < 0 ? st : &lst;
244 aint = htonl( afpd_st_cnid ( lstp ) );
246 aint = htonl(CNID(lstp, 1));
247 #endif /* DID_MTAB */
248 #endif /* USE_LASTDID */
250 #if AD_VERSION > AD_VERSION1
252 #endif /* AD_VERSION > AD_VERSION1 */
253 memcpy(data, &aint, sizeof( aint ));
254 data += sizeof( aint );
258 aint = htonl( st->st_size );
259 memcpy(data, &aint, sizeof( aint ));
260 data += sizeof( aint );
265 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
269 memcpy(data, &aint, sizeof( aint ));
270 data += sizeof( aint );
273 /* Current client needs ProDOS info block for this file.
274 Use simple heuristic and let the Mac "type" string tell
275 us what the PD file code should be. Everything gets a
276 subtype of 0x0000 unless the original value was hashed
277 to "pXYZ" when we created it. See IA, Ver 2.
279 case FILPBIT_PDINFO :
281 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
283 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
287 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
291 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
295 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
299 else if ( fdType[0] == 'p' ) {
301 ashort = (fdType[2] * 256) + fdType[3];
315 memcpy(data, &ashort, sizeof( ashort ));
316 data += sizeof( ashort );
317 memset(data, 0, sizeof( ashort ));
318 data += sizeof( ashort );
323 ad_close( adp, ADFLAGS_HF );
325 return( AFPERR_BITMAP );
331 ashort = htons( data - buf );
332 memcpy(nameoff, &ashort, sizeof( ashort ));
333 if ((aint = strlen( path )) > MACFILELEN)
336 memcpy(data, path, aint );
340 ad_close( adp, ADFLAGS_HF );
342 *buflen = data - buf;
345 syslog(LOG_INFO, "end getfilparams:");
351 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
354 int ibuflen, *rbuflen;
357 struct adouble ad, *adp;
362 int creatf, did, openf, retvalue = AFP_OK;
366 #endif /* FORCE_UIDGID */
369 syslog(LOG_INFO, "begin afp_createfile:");
374 creatf = (unsigned char) *ibuf++;
376 memcpy(&vid, ibuf, sizeof( vid ));
377 ibuf += sizeof( vid );
379 if (( vol = getvolbyvid( vid )) == NULL ) {
380 return( AFPERR_PARAM );
383 if (vol->v_flags & AFPVOL_RO)
386 memcpy(&did, ibuf, sizeof( did));
387 ibuf += sizeof( did );
389 if (( dir = dirsearch( vol, did )) == NULL ) {
390 return( AFPERR_NOOBJ );
393 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
394 return( AFPERR_NOOBJ );
397 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
398 strpbrk(path, MSWINDOWS_BADCHARS))
401 upath = mtoupath(vol, path);
403 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
406 if (!validupath(vol, upath))
409 if ((of = of_findname(vol, curdir, path))) {
412 memset(&ad, 0, sizeof(ad));
416 /* on a hard create, fail if file exists and is open */
417 if ((stat(upath, &st) == 0) && of)
419 openf = O_RDWR|O_CREAT|O_TRUNC;
421 openf = O_RDWR|O_CREAT|O_EXCL;
426 /* preserve current euid, egid */
427 save_uidgid ( uidgid );
429 /* perform all switching of users */
432 #endif /* FORCE_UIDGID */
434 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
435 openf, 0666, adp) < 0 ) {
439 /* bring everything back to old euid, egid */
440 restore_uidgid ( uidgid );
441 #endif /* FORCE_UIDGID */
442 return( AFPERR_EXIST );
445 /* bring everything back to old euid, egid */
446 restore_uidgid ( uidgid );
447 #endif /* FORCE_UIDGID */
448 return( AFPERR_ACCESS );
450 /* on noadouble volumes, just creating the data fork is ok */
451 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
452 goto createfile_done;
456 /* bring everything back to old euid, egid */
457 restore_uidgid ( uidgid );
458 #endif /* FORCE_UIDGID */
459 return( AFPERR_PARAM );
463 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
464 memcpy(ad_entry( adp, ADEID_NAME ), path,
465 ad_getentrylen( adp, ADEID_NAME ));
466 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
467 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
472 if (vol->v_flags & AFPVOL_DROPBOX) {
473 retvalue = matchfile2dirperms(upath, vol, did);
475 #endif /* DROPKLUDGE */
477 setvoltime(obj, vol );
480 syslog(LOG_INFO, "end afp_createfile");
484 /* bring everything back to old euid, egid */
485 restore_uidgid ( uidgid );
486 #endif /* FORCE_UIDGID */
491 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
494 int ibuflen, *rbuflen;
500 u_int16_t vid, bitmap;
503 syslog(LOG_INFO, "begin afp_setfilparams:");
509 memcpy(&vid, ibuf, sizeof( vid ));
510 ibuf += sizeof( vid );
511 if (( vol = getvolbyvid( vid )) == NULL ) {
512 return( AFPERR_PARAM );
515 if (vol->v_flags & AFPVOL_RO)
518 memcpy(&did, ibuf, sizeof( did ));
519 ibuf += sizeof( did );
520 if (( dir = dirsearch( vol, did )) == NULL ) {
521 return( AFPERR_NOOBJ );
524 memcpy(&bitmap, ibuf, sizeof( bitmap ));
525 bitmap = ntohs( bitmap );
526 ibuf += sizeof( bitmap );
528 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
529 return( AFPERR_NOOBJ );
532 if ((u_long)ibuf & 1 ) {
536 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
537 setvoltime(obj, vol );
541 syslog(LOG_INFO, "end afp_setfilparams:");
548 int setfilparams(vol, path, bitmap, buf )
553 struct adouble ad, *adp;
556 int bit = 0, isad = 1, err = AFP_OK;
558 u_char achar, *fdType, xyy[4];
559 u_int16_t ashort, bshort;
566 uidgid = malloc(sizeof(uidgidset));
567 #endif /* FORCE_UIDGID */
570 syslog(LOG_INFO, "begin setfilparams:");
573 upath = mtoupath(vol, path);
574 if ((of = of_findname(vol, curdir, path))) {
577 memset(&ad, 0, sizeof(ad));
582 save_uidgid ( uidgid );
584 #endif /* FORCE_UIDGID */
586 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
587 O_RDWR|O_CREAT, 0666, adp) < 0) {
588 /* for some things, we don't need an adouble header */
589 if (bitmap & ~(1<<FILPBIT_MDATE)) {
591 restore_uidgid ( uidgid );
592 #endif /* FORCE_UIDGID */
593 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
596 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
597 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
598 memcpy(ad_entry( adp, ADEID_NAME ), path,
599 ad_getentrylen( adp, ADEID_NAME ));
602 while ( bitmap != 0 ) {
603 while (( bitmap & 1 ) == 0 ) {
610 memcpy(&ashort, buf, sizeof( ashort ));
611 ad_getattr(adp, &bshort);
612 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
613 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
617 ad_setattr(adp, bshort);
618 buf += sizeof( ashort );
622 memcpy(&aint, buf, sizeof(aint));
623 ad_setdate(adp, AD_DATE_CREATE, aint);
624 buf += sizeof( aint );
628 memcpy(&aint, buf, sizeof( aint ));
630 ad_setdate(adp, AD_DATE_MODIFY, aint);
631 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
633 buf += sizeof( aint );
637 memcpy(&aint, buf, sizeof(aint));
638 ad_setdate(adp, AD_DATE_BACKUP, aint);
639 buf += sizeof( aint );
643 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
644 && (em = getextmap( path )) &&
645 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
646 (memcmp(buf + 4, em->em_creator,
647 sizeof( em->em_creator )) == 0)) {
648 memcpy(buf, ufinderi, 8 );
650 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
654 /* Client needs to set the ProDOS file info for this file.
655 Use defined strings for the simple cases, and convert
656 all else into pXYY per Inside Appletalk. Always set
657 the creator as "pdos". <shirsch@ibm.net> */
658 case FILPBIT_PDINFO :
661 memcpy(&ashort, buf, sizeof( ashort ));
662 ashort = ntohs( ashort );
665 switch ( (unsigned int) achar )
668 fdType = ( u_char *) "TEXT";
672 fdType = ( u_char *) "PSYS";
676 fdType = ( u_char *) "PS16";
680 fdType = ( u_char *) "BINA";
684 xyy[0] = ( u_char ) 'p';
686 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
687 xyy[3] = ( u_char ) ashort & 0xff;
692 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
693 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
699 goto setfilparam_done;
708 ad_flush( adp, ADFLAGS_HF );
709 ad_close( adp, ADFLAGS_HF );
712 restore_uidgid ( uidgid );
713 #endif /* FORCE_UIDGID */
718 syslog(LOG_INFO, "end setfilparams:");
725 * renamefile and copyfile take the old and new unix pathnames
726 * and the new mac name.
727 * NOTE: if we have to copy a file instead of renaming it, locks
730 int renamefile(src, dst, newname, noadouble )
731 char *src, *dst, *newname;
735 char adsrc[ MAXPATHLEN + 1];
739 * Note that this is only checking the existance of the data file,
740 * not the header file. The thinking is that if the data file doesn't
741 * exist, but the header file does, the right thing to do is remove
742 * the data file silently.
745 /* existence check moved to afp_moveandrename */
748 syslog (LOG_INFO, "begin renamefile:");
751 if ( rename( src, dst ) < 0 ) {
754 return( AFPERR_NOOBJ );
757 return( AFPERR_ACCESS );
760 case EXDEV : /* Cross device move -- try copy */
761 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
765 return deletefile( src );
767 return( AFPERR_PARAM );
771 strcpy( adsrc, ad_path( src, 0 ));
774 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
779 /* check for a source appledouble header. if it exists, make
780 * a dest appledouble directory and do the rename again. */
781 memset(&ad, 0, sizeof(ad));
782 if (rc || stat(adsrc, &st) ||
783 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
786 ad_close(&ad, ADFLAGS_HF);
790 return( AFPERR_ACCESS );
794 return( AFPERR_PARAM );
798 memset(&ad, 0, sizeof(ad));
799 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
802 return( AFPERR_NOOBJ );
804 return( AFPERR_ACCESS );
808 return( AFPERR_PARAM );
812 len = strlen( newname );
813 ad_setentrylen( &ad, ADEID_NAME, len );
814 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
815 ad_flush( &ad, ADFLAGS_HF );
816 ad_close( &ad, ADFLAGS_HF );
819 syslog (LOG_INFO, "end renamefile:");
825 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
828 int ibuflen, *rbuflen;
832 char *newname, *path, *p;
833 u_int32_t sdid, ddid;
834 int plen, err, retvalue = AFP_OK;
835 u_int16_t svid, dvid;
838 syslog (LOG_INFO, "begin afp_copyfile:");
844 memcpy(&svid, ibuf, sizeof( svid ));
845 ibuf += sizeof( svid );
846 if (( vol = getvolbyvid( svid )) == NULL ) {
847 return( AFPERR_PARAM );
850 memcpy(&sdid, ibuf, sizeof( sdid ));
851 ibuf += sizeof( sdid );
852 if (( dir = dirsearch( vol, sdid )) == NULL ) {
853 return( AFPERR_PARAM );
856 memcpy(&dvid, ibuf, sizeof( dvid ));
857 ibuf += sizeof( dvid );
858 memcpy(&ddid, ibuf, sizeof( ddid ));
859 ibuf += sizeof( ddid );
861 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
862 return( AFPERR_NOOBJ );
864 if ( *path == '\0' ) {
865 return( AFPERR_BADTYPE );
868 /* don't allow copies when the file is open.
869 * XXX: the spec only calls for read/deny write access.
870 * however, copyfile doesn't have any of that info,
871 * and locks need to stay coherent. as a result,
872 * we just balk if the file is opened already. */
873 if (of_findname(vol, curdir, path))
874 return AFPERR_DENYCONF;
876 newname = obj->newtmp;
877 strcpy( newname, path );
879 p = ctoupath( vol, curdir, newname );
881 if (( vol = getvolbyvid( dvid )) == NULL ) {
882 return( AFPERR_PARAM );
885 if (vol->v_flags & AFPVOL_RO)
888 if (( dir = dirsearch( vol, ddid )) == NULL ) {
889 return( AFPERR_PARAM );
892 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
893 return( AFPERR_NOOBJ );
895 if ( *path != '\0' ) {
896 return( AFPERR_BADTYPE );
899 /* one of the handful of places that knows about the path type */
900 if ( *ibuf++ != 2 ) {
901 return( AFPERR_PARAM );
903 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
904 strncpy( newname, ibuf, plen );
905 newname[ plen ] = '\0';
908 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
909 vol_noadouble(vol))) < 0 ) {
913 setvoltime(obj, vol );
916 if (vol->v_flags & AFPVOL_DROPBOX) {
917 retvalue=matchfile2dirperms(newname, vol, sdid);
919 #endif /* DROPKLUDGE */
922 syslog (LOG_INFO, "end afp_copyfile:");
929 static __inline__ int copy_all(const int dfd, const void *buf,
935 syslog(LOG_INFO, "begin copy_all:");
939 if ((cc = write(dfd, buf, buflen)) < 0) {
957 syslog(LOG_INFO, "end copy_all:");
963 /* XXX: this needs to use ad_open and ad_lock. so, we need to
964 * pass in vol and path */
965 int copyfile(src, dst, newname, noadouble )
966 char *src, *dst, *newname;
972 int sfd, dfd, len, err = AFP_OK;
976 syslog(LOG_INFO, "begin copyfile:");
980 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
983 break; /* just copy the data fork */
985 return( AFPERR_ACCESS );
987 return( AFPERR_PARAM );
990 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
991 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
995 return( AFPERR_NOOBJ );
997 return( AFPERR_ACCESS );
1001 return( AFPERR_PARAM );
1006 #ifdef SENDFILE_FLAVOR_LINUX
1007 if (fstat(sfd, &st) == 0) {
1008 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1022 goto copyheader_done;
1024 #endif /* SENDFILE_FLAVOR_LINUX */
1026 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1033 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1041 unlink(ad_path(dst, ADFLAGS_HF));
1047 /* data fork copying */
1048 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1051 return( AFPERR_NOOBJ );
1053 return( AFPERR_ACCESS );
1055 return( AFPERR_PARAM );
1059 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1063 return( AFPERR_NOOBJ );
1065 return( AFPERR_ACCESS );
1067 return AFPERR_VLOCK;
1069 return( AFPERR_PARAM );
1073 #ifdef SENDFILE_FLAVOR_LINUX
1074 if (fstat(sfd, &st) == 0) {
1075 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1088 #endif /* SENDFILE_FLAVOR_LINUX */
1091 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1099 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1108 unlink(ad_path(dst, ADFLAGS_HF));
1114 memset(&ad, 0, sizeof(ad));
1115 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1119 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1121 return( AFPERR_ACCESS );
1123 return AFPERR_VLOCK;
1125 return( AFPERR_PARAM );
1129 len = strlen( newname );
1130 ad_setentrylen( &ad, ADEID_NAME, len );
1131 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1132 ad_flush( &ad, ADFLAGS_HF );
1133 ad_close( &ad, ADFLAGS_HF );
1137 syslog(LOG_INFO, "end copyfile:");
1144 int deletefile( file )
1148 int adflags, err = AFP_OK;
1149 int locktype = ADLOCK_WR;
1150 int openmode = O_RDWR;
1153 syslog(LOG_INFO, "begin deletefile:");
1158 * If can't open read/write then try again read-only. If it's open
1159 * read-only, we must do a read lock instead of a write lock.
1161 /* try to open both at once */
1162 adflags = ADFLAGS_DF|ADFLAGS_HF;
1163 memset(&ad, 0, sizeof(ad));
1164 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1167 adflags = ADFLAGS_DF;
1168 /* that failed. now try to open just the data fork */
1169 memset(&ad, 0, sizeof(ad));
1170 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1173 return AFPERR_NOOBJ;
1175 if(openmode == O_RDWR) {
1176 openmode = O_RDONLY;
1177 locktype = ADLOCK_RD;
1180 return AFPERR_ACCESS;
1183 return AFPERR_VLOCK;
1185 return AFPERR_PARAM;
1191 if(openmode == O_RDWR) {
1192 openmode = O_RDONLY;
1193 locktype = ADLOCK_RD;
1196 return AFPERR_ACCESS;
1199 return AFPERR_VLOCK;
1201 return( AFPERR_PARAM );
1204 break; /* from the while */
1207 if ((adflags & ADFLAGS_HF) &&
1208 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1209 ad_close( &ad, adflags );
1210 return( AFPERR_BUSY );
1213 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1218 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1222 err = AFPERR_ACCESS;
1235 if ( unlink( file ) < 0 ) {
1239 err = AFPERR_ACCESS;
1253 if (adflags & ADFLAGS_HF)
1254 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1255 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1256 ad_close( &ad, adflags );
1259 syslog(LOG_INFO, "end deletefile:");
1266 #if AD_VERSION > AD_VERSION1
1267 /* return a file id */
1268 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1271 int ibuflen, *rbuflen;
1283 syslog(LOG_INFO, "begin afp_createid:");
1289 memcpy(&vid, ibuf, sizeof(vid));
1290 ibuf += sizeof(vid);
1292 if (( vol = getvolbyvid( vid )) == NULL ) {
1293 return( AFPERR_PARAM);
1296 if (vol->v_flags & AFPVOL_RO)
1297 return AFPERR_VLOCK;
1299 memcpy(&did, ibuf, sizeof( did ));
1300 ibuf += sizeof(did);
1302 if (( dir = dirsearch( vol, did )) == NULL ) {
1303 return( AFPERR_PARAM );
1306 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1307 return( AFPERR_PARAM );
1310 if ( *path == '\0' ) {
1311 return( AFPERR_BADTYPE );
1314 upath = mtoupath(vol, path);
1315 if (stat(upath, &st) < 0) {
1319 return AFPERR_ACCESS;
1321 return AFPERR_NOOBJ;
1323 return AFPERR_PARAM;
1327 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1328 memcpy(rbuf, &id, sizeof(id));
1329 *rbuflen = sizeof(id);
1330 return AFPERR_EXISTID;
1333 memset(&ad, 0, sizeof(ad));
1334 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1337 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1338 ad_close(&ad, ADFLAGS_HF);
1341 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1342 memcpy(rbuf, &id, sizeof(id));
1343 *rbuflen = sizeof(id);
1348 syslog(LOG_INFO, "ending afp_createid...:");
1353 return AFPERR_VLOCK;
1357 return AFPERR_ACCESS;
1360 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1361 return AFPERR_PARAM;
1365 /* resolve a file id */
1366 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1369 int ibuflen, *rbuflen;
1377 u_int16_t vid, bitmap;
1380 syslog(LOG_INFO, "begin afp_resolveid:");
1386 memcpy(&vid, ibuf, sizeof(vid));
1387 ibuf += sizeof(vid);
1389 if (( vol = getvolbyvid( vid )) == NULL ) {
1390 return( AFPERR_PARAM);
1393 memcpy(&id, ibuf, sizeof( id ));
1396 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1397 return AFPERR_BADID;
1400 if (( dir = dirsearch( vol, id )) == NULL ) {
1401 return( AFPERR_PARAM );
1404 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1408 return AFPERR_ACCESS;
1412 return AFPERR_PARAM;
1416 /* directories are bad */
1417 if (S_ISDIR(st.st_mode))
1418 return AFPERR_BADTYPE;
1420 memcpy(&bitmap, ibuf, sizeof(bitmap));
1421 bitmap = ntohs( bitmap );
1423 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1424 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1427 *rbuflen = buflen + sizeof(bitmap);
1428 memcpy(rbuf, ibuf, sizeof(bitmap));
1431 syslog(LOG_INFO, "end afp_resolveid:");
1437 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1440 int ibuflen, *rbuflen;
1451 syslog(LOG_INFO, "begin afp_deleteid:");
1457 memcpy(&vid, ibuf, sizeof(vid));
1458 ibuf += sizeof(vid);
1460 if (( vol = getvolbyvid( vid )) == NULL ) {
1461 return( AFPERR_PARAM);
1464 if (vol->v_flags & AFPVOL_RO)
1465 return AFPERR_VLOCK;
1467 memcpy(&id, ibuf, sizeof( id ));
1470 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1474 if (( dir = dirsearch( vol, id )) == NULL ) {
1475 return( AFPERR_PARAM );
1479 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1483 return AFPERR_ACCESS;
1485 /* still try to delete the id */
1489 return AFPERR_PARAM;
1493 /* directories are bad */
1494 if (S_ISDIR(st.st_mode))
1495 return AFPERR_BADTYPE;
1497 if (cnid_delete(vol->v_db, id)) {
1500 return AFPERR_VLOCK;
1503 return AFPERR_ACCESS;
1505 return AFPERR_PARAM;
1510 syslog(LOG_INFO, "end afp_deleteid:");
1515 #endif /* AD_VERSION > AD_VERSION1 */
1517 #define APPLETEMP ".AppleTempXXXXXX"
1519 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1522 int ibuflen, *rbuflen;
1524 struct stat srcst, destst;
1526 struct dir *dir, *sdir;
1527 char *spath, temp[17], *path, *p;
1528 char *supath, *upath;
1530 #if AD_VERSION > AD_VERSION1
1532 #endif /* AD_VERSION > AD_VERSION1 */
1537 syslog(LOG_INFO, "begin afp_exchangefiles:");
1543 memcpy(&vid, ibuf, sizeof(vid));
1544 ibuf += sizeof(vid);
1546 if (( vol = getvolbyvid( vid )) == NULL ) {
1547 return( AFPERR_PARAM);
1550 if (vol->v_flags & AFPVOL_RO)
1551 return AFPERR_VLOCK;
1553 /* source and destination dids */
1554 memcpy(&sid, ibuf, sizeof(sid));
1555 ibuf += sizeof(sid);
1556 memcpy(&did, ibuf, sizeof(did));
1557 ibuf += sizeof(did);
1560 if ((dir = dirsearch( vol, sid )) == NULL ) {
1561 return( AFPERR_PARAM );
1564 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1565 return( AFPERR_PARAM );
1568 if ( *path == '\0' ) {
1569 return( AFPERR_BADTYPE );
1572 upath = mtoupath(vol, path);
1573 if (stat(upath, &srcst) < 0) {
1579 return AFPERR_ACCESS;
1581 return AFPERR_PARAM;
1585 /* save some stuff */
1587 spath = obj->oldtmp;
1588 supath = obj->newtmp;
1589 strcpy(spath, path);
1590 strcpy(supath, upath); /* this is for the cnid changing */
1591 p = ctoupath( vol, sdir, spath);
1593 /* look for the source cnid. if it doesn't exist, don't worry about
1595 #if AD_VERSION > AD_VERSION1
1596 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1597 slen = strlen(supath));
1598 #endif /* AD_VERSION > AD_VERSION1 */
1600 if (( dir = dirsearch( vol, did )) == NULL ) {
1601 return( AFPERR_PARAM );
1604 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1605 return( AFPERR_PARAM );
1608 if ( *path == '\0' ) {
1609 return( AFPERR_BADTYPE );
1612 /* FPExchangeFiles is the only call that can return the SameObj
1614 if ((curdir == sdir) && strcmp(spath, path) == 0)
1615 return AFPERR_SAMEOBJ;
1617 upath = mtoupath(vol, path);
1618 if (stat(upath, &destst) < 0) {
1624 return AFPERR_ACCESS;
1626 return AFPERR_PARAM;
1630 #if AD_VERSION > AD_VERSION1
1631 /* look for destination id. */
1632 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1633 dlen = strlen(upath));
1634 #endif /* AD_VERSION > AD_VERSION1 */
1636 /* construct a temp name.
1637 * NOTE: the temp file will be in the dest file's directory. it
1638 * will also be inaccessible from AFP. */
1639 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1643 /* now, quickly rename the file. we error if we can't. */
1644 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1645 goto err_exchangefile;
1646 of_rename(vol, sdir, spath, curdir, temp);
1648 /* rename destination to source */
1649 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1650 goto err_src_to_tmp;
1651 of_rename(vol, curdir, path, sdir, spath);
1653 /* rename temp to destination */
1654 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1655 goto err_dest_to_src;
1656 of_rename(vol, curdir, temp, curdir, path);
1658 #if AD_VERSION > AD_VERSION1
1659 /* id's need switching. src -> dest and dest -> src. */
1660 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1661 upath, dlen) < 0)) {
1665 err = AFPERR_ACCESS;
1669 goto err_temp_to_dest;
1672 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1673 supath, slen) < 0)) {
1677 err = AFPERR_ACCESS;
1683 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1684 goto err_temp_to_dest;
1686 #endif /* AD_VERSION > AD_VERSION1 */
1689 syslog(LOG_INFO, "ending afp_exchangefiles:");
1695 /* all this stuff is so that we can unwind a failed operation
1698 /* rename dest to temp */
1699 renamefile(upath, temp, temp, vol_noadouble(vol));
1700 of_rename(vol, curdir, upath, curdir, temp);
1703 /* rename source back to dest */
1704 renamefile(p, upath, path, vol_noadouble(vol));
1705 of_rename(vol, sdir, spath, curdir, path);
1708 /* rename temp back to source */
1709 renamefile(temp, p, spath, vol_noadouble(vol));
1710 of_rename(vol, curdir, temp, sdir, spath);