2 * $Id: file.c,v 1.28 2001-09-04 13:52:45 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>
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 /* check for vetoed filenames */
410 if (veto_file(vol->v_veto, upath))
413 if ((of = of_findname(vol, curdir, path))) {
416 memset(&ad, 0, sizeof(ad));
420 /* on a hard create, fail if file exists and is open */
421 if ((stat(upath, &st) == 0) && of)
423 openf = O_RDWR|O_CREAT|O_TRUNC;
425 openf = O_RDWR|O_CREAT|O_EXCL;
430 /* preserve current euid, egid */
431 save_uidgid ( uidgid );
433 /* perform all switching of users */
436 #endif /* FORCE_UIDGID */
438 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
439 openf, 0666, adp) < 0 ) {
443 /* bring everything back to old euid, egid */
444 restore_uidgid ( uidgid );
445 #endif /* FORCE_UIDGID */
446 return( AFPERR_EXIST );
449 /* bring everything back to old euid, egid */
450 restore_uidgid ( uidgid );
451 #endif /* FORCE_UIDGID */
452 return( AFPERR_ACCESS );
454 /* on noadouble volumes, just creating the data fork is ok */
455 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
456 goto createfile_done;
460 /* bring everything back to old euid, egid */
461 restore_uidgid ( uidgid );
462 #endif /* FORCE_UIDGID */
463 return( AFPERR_PARAM );
467 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
468 memcpy(ad_entry( adp, ADEID_NAME ), path,
469 ad_getentrylen( adp, ADEID_NAME ));
470 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
471 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
476 if (vol->v_flags & AFPVOL_DROPBOX) {
477 retvalue = matchfile2dirperms(upath, vol, did);
479 #endif /* DROPKLUDGE */
481 setvoltime(obj, vol );
484 syslog(LOG_INFO, "end afp_createfile");
488 /* bring everything back to old euid, egid */
489 restore_uidgid ( uidgid );
490 #endif /* FORCE_UIDGID */
495 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
498 int ibuflen, *rbuflen;
504 u_int16_t vid, bitmap;
507 syslog(LOG_INFO, "begin afp_setfilparams:");
513 memcpy(&vid, ibuf, sizeof( vid ));
514 ibuf += sizeof( vid );
515 if (( vol = getvolbyvid( vid )) == NULL ) {
516 return( AFPERR_PARAM );
519 if (vol->v_flags & AFPVOL_RO)
522 memcpy(&did, ibuf, sizeof( did ));
523 ibuf += sizeof( did );
524 if (( dir = dirsearch( vol, did )) == NULL ) {
525 return( AFPERR_NOOBJ );
528 memcpy(&bitmap, ibuf, sizeof( bitmap ));
529 bitmap = ntohs( bitmap );
530 ibuf += sizeof( bitmap );
532 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
533 return( AFPERR_NOOBJ );
536 if ((u_long)ibuf & 1 ) {
540 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
541 setvoltime(obj, vol );
545 syslog(LOG_INFO, "end afp_setfilparams:");
552 int setfilparams(struct vol *vol,
553 char *path, u_int16_t bitmap, char *buf )
555 struct adouble ad, *adp;
558 int bit = 0, isad = 1, err = AFP_OK;
560 u_char achar, *fdType, xyy[4];
561 u_int16_t ashort, bshort;
568 uidgid = malloc(sizeof(uidgidset));
569 #endif /* FORCE_UIDGID */
572 syslog(LOG_INFO, "begin setfilparams:");
575 upath = mtoupath(vol, path);
576 if ((of = of_findname(vol, curdir, path))) {
579 memset(&ad, 0, sizeof(ad));
584 save_uidgid ( uidgid );
586 #endif /* FORCE_UIDGID */
588 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
589 O_RDWR|O_CREAT, 0666, adp) < 0) {
590 /* for some things, we don't need an adouble header */
591 if (bitmap & ~(1<<FILPBIT_MDATE)) {
593 restore_uidgid ( uidgid );
594 #endif /* FORCE_UIDGID */
595 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
598 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
599 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
600 memcpy(ad_entry( adp, ADEID_NAME ), path,
601 ad_getentrylen( adp, ADEID_NAME ));
604 while ( bitmap != 0 ) {
605 while (( bitmap & 1 ) == 0 ) {
612 memcpy(&ashort, buf, sizeof( ashort ));
613 ad_getattr(adp, &bshort);
614 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
615 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
619 ad_setattr(adp, bshort);
620 buf += sizeof( ashort );
624 memcpy(&aint, buf, sizeof(aint));
625 ad_setdate(adp, AD_DATE_CREATE, aint);
626 buf += sizeof( aint );
630 memcpy(&aint, buf, sizeof( aint ));
632 ad_setdate(adp, AD_DATE_MODIFY, aint);
633 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
635 buf += sizeof( aint );
639 memcpy(&aint, buf, sizeof(aint));
640 ad_setdate(adp, AD_DATE_BACKUP, aint);
641 buf += sizeof( aint );
645 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
646 && (em = getextmap( path )) &&
647 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
648 (memcmp(buf + 4, em->em_creator,
649 sizeof( em->em_creator )) == 0)) {
650 memcpy(buf, ufinderi, 8 );
652 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
656 /* Client needs to set the ProDOS file info for this file.
657 Use defined strings for the simple cases, and convert
658 all else into pXYY per Inside Appletalk. Always set
659 the creator as "pdos". <shirsch@ibm.net> */
660 case FILPBIT_PDINFO :
663 memcpy(&ashort, buf, sizeof( ashort ));
664 ashort = ntohs( ashort );
667 switch ( (unsigned int) achar )
670 fdType = ( u_char *) "TEXT";
674 fdType = ( u_char *) "PSYS";
678 fdType = ( u_char *) "PS16";
682 fdType = ( u_char *) "BINA";
686 xyy[0] = ( u_char ) 'p';
688 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
689 xyy[3] = ( u_char ) ashort & 0xff;
694 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
695 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
701 goto setfilparam_done;
710 ad_flush( adp, ADFLAGS_HF );
711 ad_close( adp, ADFLAGS_HF );
714 restore_uidgid ( uidgid );
715 #endif /* FORCE_UIDGID */
720 syslog(LOG_INFO, "end setfilparams:");
727 * renamefile and copyfile take the old and new unix pathnames
728 * and the new mac name.
729 * NOTE: if we have to copy a file instead of renaming it, locks
732 int renamefile(src, dst, newname, noadouble )
733 char *src, *dst, *newname;
737 char adsrc[ MAXPATHLEN + 1];
741 * Note that this is only checking the existance of the data file,
742 * not the header file. The thinking is that if the data file doesn't
743 * exist, but the header file does, the right thing to do is remove
744 * the data file silently.
747 /* existence check moved to afp_moveandrename */
750 syslog (LOG_INFO, "begin renamefile:");
753 if ( rename( src, dst ) < 0 ) {
756 return( AFPERR_NOOBJ );
759 return( AFPERR_ACCESS );
762 case EXDEV : /* Cross device move -- try copy */
763 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
767 return deletefile( src );
769 return( AFPERR_PARAM );
773 strcpy( adsrc, ad_path( src, 0 ));
776 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
781 /* check for a source appledouble header. if it exists, make
782 * a dest appledouble directory and do the rename again. */
783 memset(&ad, 0, sizeof(ad));
784 if (rc || stat(adsrc, &st) ||
785 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
788 ad_close(&ad, ADFLAGS_HF);
792 return( AFPERR_ACCESS );
796 return( AFPERR_PARAM );
800 memset(&ad, 0, sizeof(ad));
801 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
804 return( AFPERR_NOOBJ );
806 return( AFPERR_ACCESS );
810 return( AFPERR_PARAM );
814 len = strlen( newname );
815 ad_setentrylen( &ad, ADEID_NAME, len );
816 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
817 ad_flush( &ad, ADFLAGS_HF );
818 ad_close( &ad, ADFLAGS_HF );
821 syslog (LOG_INFO, "end renamefile:");
827 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
830 int ibuflen, *rbuflen;
834 char *newname, *path, *p;
835 u_int32_t sdid, ddid;
836 int plen, err, retvalue = AFP_OK;
837 u_int16_t svid, dvid;
840 syslog (LOG_INFO, "begin afp_copyfile:");
846 memcpy(&svid, ibuf, sizeof( svid ));
847 ibuf += sizeof( svid );
848 if (( vol = getvolbyvid( svid )) == NULL ) {
849 return( AFPERR_PARAM );
852 memcpy(&sdid, ibuf, sizeof( sdid ));
853 ibuf += sizeof( sdid );
854 if (( dir = dirsearch( vol, sdid )) == NULL ) {
855 return( AFPERR_PARAM );
858 memcpy(&dvid, ibuf, sizeof( dvid ));
859 ibuf += sizeof( dvid );
860 memcpy(&ddid, ibuf, sizeof( ddid ));
861 ibuf += sizeof( ddid );
863 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
864 return( AFPERR_NOOBJ );
866 if ( *path == '\0' ) {
867 return( AFPERR_BADTYPE );
870 /* don't allow copies when the file is open.
871 * XXX: the spec only calls for read/deny write access.
872 * however, copyfile doesn't have any of that info,
873 * and locks need to stay coherent. as a result,
874 * we just balk if the file is opened already. */
875 if (of_findname(vol, curdir, path))
876 return AFPERR_DENYCONF;
878 newname = obj->newtmp;
879 strcpy( newname, path );
881 p = ctoupath( vol, curdir, newname );
883 if (( vol = getvolbyvid( dvid )) == NULL ) {
884 return( AFPERR_PARAM );
887 if (vol->v_flags & AFPVOL_RO)
890 if (( dir = dirsearch( vol, ddid )) == NULL ) {
891 return( AFPERR_PARAM );
894 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
895 return( AFPERR_NOOBJ );
897 if ( *path != '\0' ) {
898 return( AFPERR_BADTYPE );
901 /* one of the handful of places that knows about the path type */
902 if ( *ibuf++ != 2 ) {
903 return( AFPERR_PARAM );
905 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
906 strncpy( newname, ibuf, plen );
907 newname[ plen ] = '\0';
910 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
911 vol_noadouble(vol))) < 0 ) {
915 setvoltime(obj, vol );
918 if (vol->v_flags & AFPVOL_DROPBOX) {
919 retvalue=matchfile2dirperms(newname, vol, sdid);
921 #endif /* DROPKLUDGE */
924 syslog (LOG_INFO, "end afp_copyfile:");
931 static __inline__ int copy_all(const int dfd, const void *buf,
937 syslog(LOG_INFO, "begin copy_all:");
941 if ((cc = write(dfd, buf, buflen)) < 0) {
959 syslog(LOG_INFO, "end copy_all:");
965 /* XXX: this needs to use ad_open and ad_lock. so, we need to
966 * pass in vol and path */
967 int copyfile(src, dst, newname, noadouble )
968 char *src, *dst, *newname;
974 int sfd, dfd, len, err = AFP_OK;
978 syslog(LOG_INFO, "begin copyfile:");
982 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
985 break; /* just copy the data fork */
987 return( AFPERR_ACCESS );
989 return( AFPERR_PARAM );
992 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
993 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
997 return( AFPERR_NOOBJ );
999 return( AFPERR_ACCESS );
1001 return AFPERR_VLOCK;
1003 return( AFPERR_PARAM );
1008 #ifdef SENDFILE_FLAVOR_LINUX
1009 if (fstat(sfd, &st) == 0) {
1010 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1024 goto copyheader_done;
1026 #endif /* SENDFILE_FLAVOR_LINUX */
1028 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1035 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1043 unlink(ad_path(dst, ADFLAGS_HF));
1049 /* data fork copying */
1050 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1053 return( AFPERR_NOOBJ );
1055 return( AFPERR_ACCESS );
1057 return( AFPERR_PARAM );
1061 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1065 return( AFPERR_NOOBJ );
1067 return( AFPERR_ACCESS );
1069 return AFPERR_VLOCK;
1071 return( AFPERR_PARAM );
1075 #ifdef SENDFILE_FLAVOR_LINUX
1076 if (fstat(sfd, &st) == 0) {
1077 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1090 #endif /* SENDFILE_FLAVOR_LINUX */
1093 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1101 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1110 unlink(ad_path(dst, ADFLAGS_HF));
1116 memset(&ad, 0, sizeof(ad));
1117 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1121 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1123 return( AFPERR_ACCESS );
1125 return AFPERR_VLOCK;
1127 return( AFPERR_PARAM );
1131 len = strlen( newname );
1132 ad_setentrylen( &ad, ADEID_NAME, len );
1133 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1134 ad_flush( &ad, ADFLAGS_HF );
1135 ad_close( &ad, ADFLAGS_HF );
1139 syslog(LOG_INFO, "end copyfile:");
1146 int deletefile( file )
1150 int adflags, err = AFP_OK;
1151 int locktype = ADLOCK_WR;
1152 int openmode = O_RDWR;
1155 syslog(LOG_INFO, "begin deletefile:");
1160 * If can't open read/write then try again read-only. If it's open
1161 * read-only, we must do a read lock instead of a write lock.
1163 /* try to open both at once */
1164 adflags = ADFLAGS_DF|ADFLAGS_HF;
1165 memset(&ad, 0, sizeof(ad));
1166 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1169 adflags = ADFLAGS_DF;
1170 /* that failed. now try to open just the data fork */
1171 memset(&ad, 0, sizeof(ad));
1172 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1175 return AFPERR_NOOBJ;
1177 if(openmode == O_RDWR) {
1178 openmode = O_RDONLY;
1179 locktype = ADLOCK_RD;
1182 return AFPERR_ACCESS;
1185 return AFPERR_VLOCK;
1187 return AFPERR_PARAM;
1193 if(openmode == O_RDWR) {
1194 openmode = O_RDONLY;
1195 locktype = ADLOCK_RD;
1198 return AFPERR_ACCESS;
1201 return AFPERR_VLOCK;
1203 return( AFPERR_PARAM );
1206 break; /* from the while */
1209 if ((adflags & ADFLAGS_HF) &&
1210 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1211 ad_close( &ad, adflags );
1212 return( AFPERR_BUSY );
1215 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1220 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1224 err = AFPERR_ACCESS;
1237 if ( unlink( file ) < 0 ) {
1241 err = AFPERR_ACCESS;
1255 if (adflags & ADFLAGS_HF)
1256 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1257 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1258 ad_close( &ad, adflags );
1261 syslog(LOG_INFO, "end deletefile:");
1269 /* return a file id */
1270 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1273 int ibuflen, *rbuflen;
1285 syslog(LOG_INFO, "begin afp_createid:");
1291 memcpy(&vid, ibuf, sizeof(vid));
1292 ibuf += sizeof(vid);
1294 if (( vol = getvolbyvid( vid )) == NULL ) {
1295 return( AFPERR_PARAM);
1298 if (vol->v_flags & AFPVOL_RO)
1299 return AFPERR_VLOCK;
1301 memcpy(&did, ibuf, sizeof( did ));
1302 ibuf += sizeof(did);
1304 if (( dir = dirsearch( vol, did )) == NULL ) {
1305 return( AFPERR_PARAM );
1308 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1309 return( AFPERR_PARAM );
1312 if ( *path == '\0' ) {
1313 return( AFPERR_BADTYPE );
1316 upath = mtoupath(vol, path);
1317 if (stat(upath, &st) < 0) {
1321 return AFPERR_ACCESS;
1323 return AFPERR_NOOBJ;
1325 return AFPERR_PARAM;
1329 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1330 memcpy(rbuf, &id, sizeof(id));
1331 *rbuflen = sizeof(id);
1332 return AFPERR_EXISTID;
1335 #if AD_VERSION > AD_VERSION1
1336 memset(&ad, 0, sizeof(ad));
1337 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1338 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1339 ad_close(&ad, ADFLAGS_HF);
1341 #endif /* AD_VERSION > AD_VERSION1 */
1343 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1344 memcpy(rbuf, &id, sizeof(id));
1345 *rbuflen = sizeof(id);
1350 syslog(LOG_INFO, "ending afp_createid...:");
1355 return AFPERR_VLOCK;
1359 return AFPERR_ACCESS;
1362 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1363 return AFPERR_PARAM;
1367 /* resolve a file id */
1368 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1371 int ibuflen, *rbuflen;
1379 u_int16_t vid, bitmap;
1382 syslog(LOG_INFO, "begin afp_resolveid:");
1388 memcpy(&vid, ibuf, sizeof(vid));
1389 ibuf += sizeof(vid);
1391 if (( vol = getvolbyvid( vid )) == NULL ) {
1392 return( AFPERR_PARAM);
1395 memcpy(&id, ibuf, sizeof( id ));
1398 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1399 return AFPERR_BADID;
1402 if (( dir = dirsearch( vol, id )) == NULL ) {
1403 return( AFPERR_PARAM );
1406 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1410 return AFPERR_ACCESS;
1414 return AFPERR_PARAM;
1418 /* directories are bad */
1419 if (S_ISDIR(st.st_mode))
1420 return AFPERR_BADTYPE;
1422 memcpy(&bitmap, ibuf, sizeof(bitmap));
1423 bitmap = ntohs( bitmap );
1425 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1426 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1429 *rbuflen = buflen + sizeof(bitmap);
1430 memcpy(rbuf, ibuf, sizeof(bitmap));
1433 syslog(LOG_INFO, "end afp_resolveid:");
1439 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1442 int ibuflen, *rbuflen;
1453 syslog(LOG_INFO, "begin afp_deleteid:");
1459 memcpy(&vid, ibuf, sizeof(vid));
1460 ibuf += sizeof(vid);
1462 if (( vol = getvolbyvid( vid )) == NULL ) {
1463 return( AFPERR_PARAM);
1466 if (vol->v_flags & AFPVOL_RO)
1467 return AFPERR_VLOCK;
1469 memcpy(&id, ibuf, sizeof( id ));
1472 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1476 if (( dir = dirsearch( vol, id )) == NULL ) {
1477 return( AFPERR_PARAM );
1481 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1485 return AFPERR_ACCESS;
1487 /* still try to delete the id */
1491 return AFPERR_PARAM;
1495 /* directories are bad */
1496 if (S_ISDIR(st.st_mode))
1497 return AFPERR_BADTYPE;
1499 if (cnid_delete(vol->v_db, id)) {
1502 return AFPERR_VLOCK;
1505 return AFPERR_ACCESS;
1507 return AFPERR_PARAM;
1512 syslog(LOG_INFO, "end afp_deleteid:");
1517 #endif /* CNID_DB */
1519 #define APPLETEMP ".AppleTempXXXXXX"
1521 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1524 int ibuflen, *rbuflen;
1526 struct stat srcst, destst;
1528 struct dir *dir, *sdir;
1529 char *spath, temp[17], *path, *p;
1530 char *supath, *upath;
1534 #endif /* CNID_DB */
1539 syslog(LOG_INFO, "begin afp_exchangefiles:");
1545 memcpy(&vid, ibuf, sizeof(vid));
1546 ibuf += sizeof(vid);
1548 if (( vol = getvolbyvid( vid )) == NULL ) {
1549 return( AFPERR_PARAM);
1552 if (vol->v_flags & AFPVOL_RO)
1553 return AFPERR_VLOCK;
1555 /* source and destination dids */
1556 memcpy(&sid, ibuf, sizeof(sid));
1557 ibuf += sizeof(sid);
1558 memcpy(&did, ibuf, sizeof(did));
1559 ibuf += sizeof(did);
1562 if ((dir = dirsearch( vol, sid )) == NULL ) {
1563 return( AFPERR_PARAM );
1566 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1567 return( AFPERR_PARAM );
1570 if ( *path == '\0' ) {
1571 return( AFPERR_BADTYPE );
1574 upath = mtoupath(vol, path);
1575 if (stat(upath, &srcst) < 0) {
1581 return AFPERR_ACCESS;
1583 return AFPERR_PARAM;
1587 /* save some stuff */
1589 spath = obj->oldtmp;
1590 supath = obj->newtmp;
1591 strcpy(spath, path);
1592 strcpy(supath, upath); /* this is for the cnid changing */
1593 p = ctoupath( vol, sdir, spath);
1595 /* look for the source cnid. if it doesn't exist, don't worry about
1598 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1599 slen = strlen(supath));
1600 #endif /* CNID_DB */
1602 if (( dir = dirsearch( vol, did )) == NULL ) {
1603 return( AFPERR_PARAM );
1606 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1607 return( AFPERR_PARAM );
1610 if ( *path == '\0' ) {
1611 return( AFPERR_BADTYPE );
1614 /* FPExchangeFiles is the only call that can return the SameObj
1616 if ((curdir == sdir) && strcmp(spath, path) == 0)
1617 return AFPERR_SAMEOBJ;
1619 upath = mtoupath(vol, path);
1620 if (stat(upath, &destst) < 0) {
1626 return AFPERR_ACCESS;
1628 return AFPERR_PARAM;
1633 /* look for destination id. */
1634 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1635 dlen = strlen(upath));
1636 #endif /* CNID_DB */
1638 /* construct a temp name.
1639 * NOTE: the temp file will be in the dest file's directory. it
1640 * will also be inaccessible from AFP. */
1641 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1645 /* now, quickly rename the file. we error if we can't. */
1646 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1647 goto err_exchangefile;
1648 of_rename(vol, sdir, spath, curdir, temp);
1650 /* rename destination to source */
1651 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1652 goto err_src_to_tmp;
1653 of_rename(vol, curdir, path, sdir, spath);
1655 /* rename temp to destination */
1656 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1657 goto err_dest_to_src;
1658 of_rename(vol, curdir, temp, curdir, path);
1661 /* id's need switching. src -> dest and dest -> src. */
1662 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1663 upath, dlen) < 0)) {
1667 err = AFPERR_ACCESS;
1671 goto err_temp_to_dest;
1674 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1675 supath, slen) < 0)) {
1679 err = AFPERR_ACCESS;
1685 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1686 goto err_temp_to_dest;
1688 #endif /* CNID_DB */
1691 syslog(LOG_INFO, "ending afp_exchangefiles:");
1697 /* all this stuff is so that we can unwind a failed operation
1700 /* rename dest to temp */
1701 renamefile(upath, temp, temp, vol_noadouble(vol));
1702 of_rename(vol, curdir, upath, curdir, temp);
1705 /* rename source back to dest */
1706 renamefile(p, upath, path, vol_noadouble(vol));
1707 of_rename(vol, sdir, spath, curdir, path);
1710 /* rename temp back to source */
1711 renamefile(temp, p, spath, vol_noadouble(vol));
1712 of_rename(vol, curdir, temp, sdir, spath);