2 * $Id: file.c,v 1.27 2001-08-27 15:26:16 uhees 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>
37 #include <atalk/cnid.h>
39 #include "directory.h"
47 /* check for mtab DID code */
49 #include "parse_mtab.h"
55 #endif /* FORCE_UIDGID */
57 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
58 * field bytes subfield bytes
61 * ioFlFndrInfo 16 -> type 4 type field
62 * creator 4 creator field
63 * flags 2 finder flags:
65 * location 4 location in window
66 * folder 2 window that contains file
68 * ioFlXFndrInfo 16 -> iconID 2 icon id
70 * script 1 script system
72 * commentID 2 comment id
73 * putawayID 4 home directory id
76 const u_char ufinderi[] = {
77 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
78 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0
83 int getfilparams(struct vol *vol,
85 char *path, struct dir *dir, struct stat *st,
86 char *buf, int *buflen )
89 struct stat hst, lst, *lstp;
90 #else /* USE_LASTDID */
92 #endif /* USE_LASTDID */
93 struct adouble ad, *adp;
96 char *data, *nameoff = NULL, *upath;
97 int bit = 0, isad = 1;
100 u_char achar, fdType[4];
103 syslog(LOG_INFO, "begin getfilparams:");
106 upath = mtoupath(vol, path);
107 if ((of = of_findname(vol, curdir, path))) {
110 memset(&ad, 0, sizeof(ad));
114 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
116 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
117 syslog( LOG_ERR, "getfilparams fstat: %s", strerror(errno) );
121 while ( bitmap != 0 ) {
122 while (( bitmap & 1 ) == 0 ) {
130 ad_getattr(adp, &ashort);
131 } else if (*upath == '.') {
132 ashort = htons(ATTRBIT_INVISIBLE);
135 memcpy(data, &ashort, sizeof( ashort ));
136 data += sizeof( u_short );
140 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
141 data += sizeof( u_int32_t );
145 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
146 aint = AD_DATE_FROM_UNIX(st->st_mtime);
147 memcpy(data, &aint, sizeof( aint ));
148 data += sizeof( aint );
152 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
153 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
154 (hst.st_mtime < st->st_mtime)) {
155 aint = AD_DATE_FROM_UNIX(st->st_mtime);
158 aint = AD_DATE_FROM_UNIX(st->st_mtime);
160 memcpy(data, &aint, sizeof( int ));
161 data += sizeof( int );
165 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
166 aint = AD_DATE_START;
167 memcpy(data, &aint, sizeof( int ));
168 data += sizeof( int );
173 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
175 memcpy(data, ufinderi, 32);
176 if (*upath == '.') { /* make it invisible */
177 ashort = htons(FINDERINFO_INVISIBLE);
178 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
182 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
183 ufinderi, 8 ) == 0)) &&
184 (em = getextmap( path ))) {
185 memcpy(data, em->em_type, sizeof( em->em_type ));
186 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
193 data += sizeof( u_int16_t );
197 memset(data, 0, sizeof(u_int16_t));
198 data += sizeof( u_int16_t );
203 #if AD_VERSION > AD_VERSION1
204 /* look in AD v2 header */
206 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
207 #endif /* AD_VERSION > AD_VERSION1 */
210 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
211 strlen(upath), aint);
216 * What a fucking mess. First thing: DID and FNUMs are
217 * in the same space for purposes of enumerate (and several
218 * other wierd places). While we consider this Apple's bug,
219 * this is the work-around: In order to maintain constant and
220 * unique DIDs and FNUMs, we monotonically generate the DIDs
221 * during the session, and derive the FNUMs from the filesystem.
222 * Since the DIDs are small, we insure that the FNUMs are fairly
223 * large by setting thier high bits to the device number.
225 * AFS already does something very similar to this for the
226 * inode number, so we don't repeat the procedure.
229 * due to complaints over did's being non-persistent,
230 * here's the current hack to provide semi-persistent
232 * 1) we reserve the first bit for file ids.
233 * 2) the next 7 bits are for the device.
234 * 3) the remaining 24 bits are for the inode.
236 * both the inode and device information are actually hashes
237 * that are then truncated to the requisite bit length.
239 * it should be okay to use lstat to deal with symlinks.
242 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
243 #else /* USE_LASTDID */
244 lstp = lstat(upath, &lst) < 0 ? st : &lst;
246 aint = htonl( afpd_st_cnid ( lstp ) );
248 aint = htonl(CNID(lstp, 1));
249 #endif /* DID_MTAB */
250 #endif /* USE_LASTDID */
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(struct vol *vol,
549 char *path, u_int16_t bitmap, char *buf )
551 struct adouble ad, *adp;
554 int bit = 0, isad = 1, err = AFP_OK;
556 u_char achar, *fdType, xyy[4];
557 u_int16_t ashort, bshort;
564 uidgid = malloc(sizeof(uidgidset));
565 #endif /* FORCE_UIDGID */
568 syslog(LOG_INFO, "begin setfilparams:");
571 upath = mtoupath(vol, path);
572 if ((of = of_findname(vol, curdir, path))) {
575 memset(&ad, 0, sizeof(ad));
580 save_uidgid ( uidgid );
582 #endif /* FORCE_UIDGID */
584 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
585 O_RDWR|O_CREAT, 0666, adp) < 0) {
586 /* for some things, we don't need an adouble header */
587 if (bitmap & ~(1<<FILPBIT_MDATE)) {
589 restore_uidgid ( uidgid );
590 #endif /* FORCE_UIDGID */
591 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
594 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
595 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
596 memcpy(ad_entry( adp, ADEID_NAME ), path,
597 ad_getentrylen( adp, ADEID_NAME ));
600 while ( bitmap != 0 ) {
601 while (( bitmap & 1 ) == 0 ) {
608 memcpy(&ashort, buf, sizeof( ashort ));
609 ad_getattr(adp, &bshort);
610 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
611 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
615 ad_setattr(adp, bshort);
616 buf += sizeof( ashort );
620 memcpy(&aint, buf, sizeof(aint));
621 ad_setdate(adp, AD_DATE_CREATE, aint);
622 buf += sizeof( aint );
626 memcpy(&aint, buf, sizeof( aint ));
628 ad_setdate(adp, AD_DATE_MODIFY, aint);
629 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
631 buf += sizeof( aint );
635 memcpy(&aint, buf, sizeof(aint));
636 ad_setdate(adp, AD_DATE_BACKUP, aint);
637 buf += sizeof( aint );
641 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
642 && (em = getextmap( path )) &&
643 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
644 (memcmp(buf + 4, em->em_creator,
645 sizeof( em->em_creator )) == 0)) {
646 memcpy(buf, ufinderi, 8 );
648 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
652 /* Client needs to set the ProDOS file info for this file.
653 Use defined strings for the simple cases, and convert
654 all else into pXYY per Inside Appletalk. Always set
655 the creator as "pdos". <shirsch@ibm.net> */
656 case FILPBIT_PDINFO :
659 memcpy(&ashort, buf, sizeof( ashort ));
660 ashort = ntohs( ashort );
663 switch ( (unsigned int) achar )
666 fdType = ( u_char *) "TEXT";
670 fdType = ( u_char *) "PSYS";
674 fdType = ( u_char *) "PS16";
678 fdType = ( u_char *) "BINA";
682 xyy[0] = ( u_char ) 'p';
684 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
685 xyy[3] = ( u_char ) ashort & 0xff;
690 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
691 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
697 goto setfilparam_done;
706 ad_flush( adp, ADFLAGS_HF );
707 ad_close( adp, ADFLAGS_HF );
710 restore_uidgid ( uidgid );
711 #endif /* FORCE_UIDGID */
716 syslog(LOG_INFO, "end setfilparams:");
723 * renamefile and copyfile take the old and new unix pathnames
724 * and the new mac name.
725 * NOTE: if we have to copy a file instead of renaming it, locks
728 int renamefile(src, dst, newname, noadouble )
729 char *src, *dst, *newname;
733 char adsrc[ MAXPATHLEN + 1];
737 * Note that this is only checking the existance of the data file,
738 * not the header file. The thinking is that if the data file doesn't
739 * exist, but the header file does, the right thing to do is remove
740 * the data file silently.
743 /* existence check moved to afp_moveandrename */
746 syslog (LOG_INFO, "begin renamefile:");
749 if ( rename( src, dst ) < 0 ) {
752 return( AFPERR_NOOBJ );
755 return( AFPERR_ACCESS );
758 case EXDEV : /* Cross device move -- try copy */
759 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
763 return deletefile( src );
765 return( AFPERR_PARAM );
769 strcpy( adsrc, ad_path( src, 0 ));
772 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
777 /* check for a source appledouble header. if it exists, make
778 * a dest appledouble directory and do the rename again. */
779 memset(&ad, 0, sizeof(ad));
780 if (rc || stat(adsrc, &st) ||
781 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
784 ad_close(&ad, ADFLAGS_HF);
788 return( AFPERR_ACCESS );
792 return( AFPERR_PARAM );
796 memset(&ad, 0, sizeof(ad));
797 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
800 return( AFPERR_NOOBJ );
802 return( AFPERR_ACCESS );
806 return( AFPERR_PARAM );
810 len = strlen( newname );
811 ad_setentrylen( &ad, ADEID_NAME, len );
812 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
813 ad_flush( &ad, ADFLAGS_HF );
814 ad_close( &ad, ADFLAGS_HF );
817 syslog (LOG_INFO, "end renamefile:");
823 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
826 int ibuflen, *rbuflen;
830 char *newname, *path, *p;
831 u_int32_t sdid, ddid;
832 int plen, err, retvalue = AFP_OK;
833 u_int16_t svid, dvid;
836 syslog (LOG_INFO, "begin afp_copyfile:");
842 memcpy(&svid, ibuf, sizeof( svid ));
843 ibuf += sizeof( svid );
844 if (( vol = getvolbyvid( svid )) == NULL ) {
845 return( AFPERR_PARAM );
848 memcpy(&sdid, ibuf, sizeof( sdid ));
849 ibuf += sizeof( sdid );
850 if (( dir = dirsearch( vol, sdid )) == NULL ) {
851 return( AFPERR_PARAM );
854 memcpy(&dvid, ibuf, sizeof( dvid ));
855 ibuf += sizeof( dvid );
856 memcpy(&ddid, ibuf, sizeof( ddid ));
857 ibuf += sizeof( ddid );
859 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
860 return( AFPERR_NOOBJ );
862 if ( *path == '\0' ) {
863 return( AFPERR_BADTYPE );
866 /* don't allow copies when the file is open.
867 * XXX: the spec only calls for read/deny write access.
868 * however, copyfile doesn't have any of that info,
869 * and locks need to stay coherent. as a result,
870 * we just balk if the file is opened already. */
871 if (of_findname(vol, curdir, path))
872 return AFPERR_DENYCONF;
874 newname = obj->newtmp;
875 strcpy( newname, path );
877 p = ctoupath( vol, curdir, newname );
879 if (( vol = getvolbyvid( dvid )) == NULL ) {
880 return( AFPERR_PARAM );
883 if (vol->v_flags & AFPVOL_RO)
886 if (( dir = dirsearch( vol, ddid )) == NULL ) {
887 return( AFPERR_PARAM );
890 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
891 return( AFPERR_NOOBJ );
893 if ( *path != '\0' ) {
894 return( AFPERR_BADTYPE );
897 /* one of the handful of places that knows about the path type */
898 if ( *ibuf++ != 2 ) {
899 return( AFPERR_PARAM );
901 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
902 strncpy( newname, ibuf, plen );
903 newname[ plen ] = '\0';
906 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
907 vol_noadouble(vol))) < 0 ) {
911 setvoltime(obj, vol );
914 if (vol->v_flags & AFPVOL_DROPBOX) {
915 retvalue=matchfile2dirperms(newname, vol, sdid);
917 #endif /* DROPKLUDGE */
920 syslog (LOG_INFO, "end afp_copyfile:");
927 static __inline__ int copy_all(const int dfd, const void *buf,
933 syslog(LOG_INFO, "begin copy_all:");
937 if ((cc = write(dfd, buf, buflen)) < 0) {
955 syslog(LOG_INFO, "end copy_all:");
961 /* XXX: this needs to use ad_open and ad_lock. so, we need to
962 * pass in vol and path */
963 int copyfile(src, dst, newname, noadouble )
964 char *src, *dst, *newname;
970 int sfd, dfd, len, err = AFP_OK;
974 syslog(LOG_INFO, "begin copyfile:");
978 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
981 break; /* just copy the data fork */
983 return( AFPERR_ACCESS );
985 return( AFPERR_PARAM );
988 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
989 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
993 return( AFPERR_NOOBJ );
995 return( AFPERR_ACCESS );
999 return( AFPERR_PARAM );
1004 #ifdef SENDFILE_FLAVOR_LINUX
1005 if (fstat(sfd, &st) == 0) {
1006 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1020 goto copyheader_done;
1022 #endif /* SENDFILE_FLAVOR_LINUX */
1024 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1031 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1039 unlink(ad_path(dst, ADFLAGS_HF));
1045 /* data fork copying */
1046 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1049 return( AFPERR_NOOBJ );
1051 return( AFPERR_ACCESS );
1053 return( AFPERR_PARAM );
1057 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1061 return( AFPERR_NOOBJ );
1063 return( AFPERR_ACCESS );
1065 return AFPERR_VLOCK;
1067 return( AFPERR_PARAM );
1071 #ifdef SENDFILE_FLAVOR_LINUX
1072 if (fstat(sfd, &st) == 0) {
1073 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1086 #endif /* SENDFILE_FLAVOR_LINUX */
1089 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1097 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1106 unlink(ad_path(dst, ADFLAGS_HF));
1112 memset(&ad, 0, sizeof(ad));
1113 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1117 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1119 return( AFPERR_ACCESS );
1121 return AFPERR_VLOCK;
1123 return( AFPERR_PARAM );
1127 len = strlen( newname );
1128 ad_setentrylen( &ad, ADEID_NAME, len );
1129 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1130 ad_flush( &ad, ADFLAGS_HF );
1131 ad_close( &ad, ADFLAGS_HF );
1135 syslog(LOG_INFO, "end copyfile:");
1142 int deletefile( file )
1146 int adflags, err = AFP_OK;
1147 int locktype = ADLOCK_WR;
1148 int openmode = O_RDWR;
1151 syslog(LOG_INFO, "begin deletefile:");
1156 * If can't open read/write then try again read-only. If it's open
1157 * read-only, we must do a read lock instead of a write lock.
1159 /* try to open both at once */
1160 adflags = ADFLAGS_DF|ADFLAGS_HF;
1161 memset(&ad, 0, sizeof(ad));
1162 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1165 adflags = ADFLAGS_DF;
1166 /* that failed. now try to open just the data fork */
1167 memset(&ad, 0, sizeof(ad));
1168 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1171 return AFPERR_NOOBJ;
1173 if(openmode == O_RDWR) {
1174 openmode = O_RDONLY;
1175 locktype = ADLOCK_RD;
1178 return AFPERR_ACCESS;
1181 return AFPERR_VLOCK;
1183 return AFPERR_PARAM;
1189 if(openmode == O_RDWR) {
1190 openmode = O_RDONLY;
1191 locktype = ADLOCK_RD;
1194 return AFPERR_ACCESS;
1197 return AFPERR_VLOCK;
1199 return( AFPERR_PARAM );
1202 break; /* from the while */
1205 if ((adflags & ADFLAGS_HF) &&
1206 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1207 ad_close( &ad, adflags );
1208 return( AFPERR_BUSY );
1211 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1216 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1220 err = AFPERR_ACCESS;
1233 if ( unlink( file ) < 0 ) {
1237 err = AFPERR_ACCESS;
1251 if (adflags & ADFLAGS_HF)
1252 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1253 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1254 ad_close( &ad, adflags );
1257 syslog(LOG_INFO, "end deletefile:");
1265 /* return a file id */
1266 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1269 int ibuflen, *rbuflen;
1281 syslog(LOG_INFO, "begin afp_createid:");
1287 memcpy(&vid, ibuf, sizeof(vid));
1288 ibuf += sizeof(vid);
1290 if (( vol = getvolbyvid( vid )) == NULL ) {
1291 return( AFPERR_PARAM);
1294 if (vol->v_flags & AFPVOL_RO)
1295 return AFPERR_VLOCK;
1297 memcpy(&did, ibuf, sizeof( did ));
1298 ibuf += sizeof(did);
1300 if (( dir = dirsearch( vol, did )) == NULL ) {
1301 return( AFPERR_PARAM );
1304 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1305 return( AFPERR_PARAM );
1308 if ( *path == '\0' ) {
1309 return( AFPERR_BADTYPE );
1312 upath = mtoupath(vol, path);
1313 if (stat(upath, &st) < 0) {
1317 return AFPERR_ACCESS;
1319 return AFPERR_NOOBJ;
1321 return AFPERR_PARAM;
1325 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1326 memcpy(rbuf, &id, sizeof(id));
1327 *rbuflen = sizeof(id);
1328 return AFPERR_EXISTID;
1331 #if AD_VERSION > AD_VERSION1
1332 memset(&ad, 0, sizeof(ad));
1333 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1334 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1335 ad_close(&ad, ADFLAGS_HF);
1337 #endif /* AD_VERSION > AD_VERSION1 */
1339 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1340 memcpy(rbuf, &id, sizeof(id));
1341 *rbuflen = sizeof(id);
1346 syslog(LOG_INFO, "ending afp_createid...:");
1351 return AFPERR_VLOCK;
1355 return AFPERR_ACCESS;
1358 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1359 return AFPERR_PARAM;
1363 /* resolve a file id */
1364 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1367 int ibuflen, *rbuflen;
1375 u_int16_t vid, bitmap;
1378 syslog(LOG_INFO, "begin afp_resolveid:");
1384 memcpy(&vid, ibuf, sizeof(vid));
1385 ibuf += sizeof(vid);
1387 if (( vol = getvolbyvid( vid )) == NULL ) {
1388 return( AFPERR_PARAM);
1391 memcpy(&id, ibuf, sizeof( id ));
1394 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1395 return AFPERR_BADID;
1398 if (( dir = dirsearch( vol, id )) == NULL ) {
1399 return( AFPERR_PARAM );
1402 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1406 return AFPERR_ACCESS;
1410 return AFPERR_PARAM;
1414 /* directories are bad */
1415 if (S_ISDIR(st.st_mode))
1416 return AFPERR_BADTYPE;
1418 memcpy(&bitmap, ibuf, sizeof(bitmap));
1419 bitmap = ntohs( bitmap );
1421 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1422 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1425 *rbuflen = buflen + sizeof(bitmap);
1426 memcpy(rbuf, ibuf, sizeof(bitmap));
1429 syslog(LOG_INFO, "end afp_resolveid:");
1435 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1438 int ibuflen, *rbuflen;
1449 syslog(LOG_INFO, "begin afp_deleteid:");
1455 memcpy(&vid, ibuf, sizeof(vid));
1456 ibuf += sizeof(vid);
1458 if (( vol = getvolbyvid( vid )) == NULL ) {
1459 return( AFPERR_PARAM);
1462 if (vol->v_flags & AFPVOL_RO)
1463 return AFPERR_VLOCK;
1465 memcpy(&id, ibuf, sizeof( id ));
1468 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1472 if (( dir = dirsearch( vol, id )) == NULL ) {
1473 return( AFPERR_PARAM );
1477 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1481 return AFPERR_ACCESS;
1483 /* still try to delete the id */
1487 return AFPERR_PARAM;
1491 /* directories are bad */
1492 if (S_ISDIR(st.st_mode))
1493 return AFPERR_BADTYPE;
1495 if (cnid_delete(vol->v_db, id)) {
1498 return AFPERR_VLOCK;
1501 return AFPERR_ACCESS;
1503 return AFPERR_PARAM;
1508 syslog(LOG_INFO, "end afp_deleteid:");
1513 #endif /* CNID_DB */
1515 #define APPLETEMP ".AppleTempXXXXXX"
1517 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1520 int ibuflen, *rbuflen;
1522 struct stat srcst, destst;
1524 struct dir *dir, *sdir;
1525 char *spath, temp[17], *path, *p;
1526 char *supath, *upath;
1530 #endif /* CNID_DB */
1535 syslog(LOG_INFO, "begin afp_exchangefiles:");
1541 memcpy(&vid, ibuf, sizeof(vid));
1542 ibuf += sizeof(vid);
1544 if (( vol = getvolbyvid( vid )) == NULL ) {
1545 return( AFPERR_PARAM);
1548 if (vol->v_flags & AFPVOL_RO)
1549 return AFPERR_VLOCK;
1551 /* source and destination dids */
1552 memcpy(&sid, ibuf, sizeof(sid));
1553 ibuf += sizeof(sid);
1554 memcpy(&did, ibuf, sizeof(did));
1555 ibuf += sizeof(did);
1558 if ((dir = dirsearch( vol, sid )) == NULL ) {
1559 return( AFPERR_PARAM );
1562 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1563 return( AFPERR_PARAM );
1566 if ( *path == '\0' ) {
1567 return( AFPERR_BADTYPE );
1570 upath = mtoupath(vol, path);
1571 if (stat(upath, &srcst) < 0) {
1577 return AFPERR_ACCESS;
1579 return AFPERR_PARAM;
1583 /* save some stuff */
1585 spath = obj->oldtmp;
1586 supath = obj->newtmp;
1587 strcpy(spath, path);
1588 strcpy(supath, upath); /* this is for the cnid changing */
1589 p = ctoupath( vol, sdir, spath);
1591 /* look for the source cnid. if it doesn't exist, don't worry about
1594 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1595 slen = strlen(supath));
1596 #endif /* CNID_DB */
1598 if (( dir = dirsearch( vol, did )) == NULL ) {
1599 return( AFPERR_PARAM );
1602 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1603 return( AFPERR_PARAM );
1606 if ( *path == '\0' ) {
1607 return( AFPERR_BADTYPE );
1610 /* FPExchangeFiles is the only call that can return the SameObj
1612 if ((curdir == sdir) && strcmp(spath, path) == 0)
1613 return AFPERR_SAMEOBJ;
1615 upath = mtoupath(vol, path);
1616 if (stat(upath, &destst) < 0) {
1622 return AFPERR_ACCESS;
1624 return AFPERR_PARAM;
1629 /* look for destination id. */
1630 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1631 dlen = strlen(upath));
1632 #endif /* CNID_DB */
1634 /* construct a temp name.
1635 * NOTE: the temp file will be in the dest file's directory. it
1636 * will also be inaccessible from AFP. */
1637 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1641 /* now, quickly rename the file. we error if we can't. */
1642 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1643 goto err_exchangefile;
1644 of_rename(vol, sdir, spath, curdir, temp);
1646 /* rename destination to source */
1647 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1648 goto err_src_to_tmp;
1649 of_rename(vol, curdir, path, sdir, spath);
1651 /* rename temp to destination */
1652 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1653 goto err_dest_to_src;
1654 of_rename(vol, curdir, temp, curdir, path);
1657 /* id's need switching. src -> dest and dest -> src. */
1658 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1659 upath, dlen) < 0)) {
1663 err = AFPERR_ACCESS;
1667 goto err_temp_to_dest;
1670 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1671 supath, slen) < 0)) {
1675 err = AFPERR_ACCESS;
1681 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1682 goto err_temp_to_dest;
1684 #endif /* CNID_DB */
1687 syslog(LOG_INFO, "ending afp_exchangefiles:");
1693 /* all this stuff is so that we can unwind a failed operation
1696 /* rename dest to temp */
1697 renamefile(upath, temp, temp, vol_noadouble(vol));
1698 of_rename(vol, curdir, upath, curdir, temp);
1701 /* rename source back to dest */
1702 renamefile(p, upath, path, vol_noadouble(vol));
1703 of_rename(vol, sdir, spath, curdir, path);
1706 /* rename temp back to source */
1707 renamefile(temp, p, spath, vol_noadouble(vol));
1708 of_rename(vol, curdir, temp, sdir, spath);