2 * $Id: file.c,v 1.35 2002-01-04 04:45:47 sibaz 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 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
52 #include <atalk/cnid.h>
54 #include "directory.h"
62 /* check for mtab DID code */
64 #include "parse_mtab.h"
70 #endif /* FORCE_UIDGID */
72 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
73 * field bytes subfield bytes
76 * ioFlFndrInfo 16 -> type 4 type field
77 * creator 4 creator field
78 * flags 2 finder flags:
80 * location 4 location in window
81 * folder 2 window that contains file
83 * ioFlXFndrInfo 16 -> iconID 2 icon id
85 * script 1 script system
87 * commentID 2 comment id
88 * putawayID 4 home directory id
91 const u_char ufinderi[] = {
92 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
93 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0
98 int getfilparams(struct vol *vol,
100 char *path, struct dir *dir, struct stat *st,
101 char *buf, int *buflen )
104 struct stat hst, lst, *lstp;
105 #else /* USE_LASTDID */
107 #endif /* USE_LASTDID */
108 struct adouble ad, *adp;
111 char *data, *nameoff = NULL, *upath;
112 int bit = 0, isad = 1;
115 u_char achar, fdType[4];
118 LOG(log_info, logtype_default, "begin getfilparams:");
121 upath = mtoupath(vol, path);
122 if ((of = of_findname(vol, curdir, path))) {
125 memset(&ad, 0, sizeof(ad));
129 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
131 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
132 LOG(log_error, logtype_default, "getfilparams fstat: %s", strerror(errno) );
136 while ( bitmap != 0 ) {
137 while (( bitmap & 1 ) == 0 ) {
145 ad_getattr(adp, &ashort);
146 } else if (*upath == '.') {
147 ashort = htons(ATTRBIT_INVISIBLE);
150 memcpy(data, &ashort, sizeof( ashort ));
151 data += sizeof( u_short );
155 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
156 data += sizeof( u_int32_t );
160 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
161 aint = AD_DATE_FROM_UNIX(st->st_mtime);
162 memcpy(data, &aint, sizeof( aint ));
163 data += sizeof( aint );
167 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
168 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
169 (hst.st_mtime < st->st_mtime)) {
170 aint = AD_DATE_FROM_UNIX(st->st_mtime);
173 aint = AD_DATE_FROM_UNIX(st->st_mtime);
175 memcpy(data, &aint, sizeof( int ));
176 data += sizeof( int );
180 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
181 aint = AD_DATE_START;
182 memcpy(data, &aint, sizeof( int ));
183 data += sizeof( int );
188 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
190 memcpy(data, ufinderi, 32);
191 if (*upath == '.') { /* make it invisible */
192 ashort = htons(FINDERINFO_INVISIBLE);
193 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
197 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
198 ufinderi, 8 ) == 0)) &&
199 (em = getextmap( path ))) {
200 memcpy(data, em->em_type, sizeof( em->em_type ));
201 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
208 data += sizeof( u_int16_t );
212 memset(data, 0, sizeof(u_int16_t));
213 data += sizeof( u_int16_t );
218 #if AD_VERSION > AD_VERSION1
219 /* look in AD v2 header */
221 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
222 #endif /* AD_VERSION > AD_VERSION1 */
225 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
226 strlen(upath), aint);
231 * What a fucking mess. First thing: DID and FNUMs are
232 * in the same space for purposes of enumerate (and several
233 * other wierd places). While we consider this Apple's bug,
234 * this is the work-around: In order to maintain constant and
235 * unique DIDs and FNUMs, we monotonically generate the DIDs
236 * during the session, and derive the FNUMs from the filesystem.
237 * Since the DIDs are small, we insure that the FNUMs are fairly
238 * large by setting thier high bits to the device number.
240 * AFS already does something very similar to this for the
241 * inode number, so we don't repeat the procedure.
244 * due to complaints over did's being non-persistent,
245 * here's the current hack to provide semi-persistent
247 * 1) we reserve the first bit for file ids.
248 * 2) the next 7 bits are for the device.
249 * 3) the remaining 24 bits are for the inode.
251 * both the inode and device information are actually hashes
252 * that are then truncated to the requisite bit length.
254 * it should be okay to use lstat to deal with symlinks.
257 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
258 #else /* USE_LASTDID */
259 lstp = lstat(upath, &lst) < 0 ? st : &lst;
261 aint = htonl( afpd_st_cnid ( lstp ) );
263 aint = htonl(CNID(lstp, 1));
264 #endif /* DID_MTAB */
265 #endif /* USE_LASTDID */
268 memcpy(data, &aint, sizeof( aint ));
269 data += sizeof( aint );
273 aint = htonl( st->st_size );
274 memcpy(data, &aint, sizeof( aint ));
275 data += sizeof( aint );
280 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
284 memcpy(data, &aint, sizeof( aint ));
285 data += sizeof( aint );
288 /* Current client needs ProDOS info block for this file.
289 Use simple heuristic and let the Mac "type" string tell
290 us what the PD file code should be. Everything gets a
291 subtype of 0x0000 unless the original value was hashed
292 to "pXYZ" when we created it. See IA, Ver 2.
294 case FILPBIT_PDINFO :
296 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
298 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
302 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
306 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
310 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
314 else if ( fdType[0] == 'p' ) {
316 ashort = (fdType[2] * 256) + fdType[3];
330 memcpy(data, &ashort, sizeof( ashort ));
331 data += sizeof( ashort );
332 memset(data, 0, sizeof( ashort ));
333 data += sizeof( ashort );
338 ad_close( adp, ADFLAGS_HF );
340 return( AFPERR_BITMAP );
346 ashort = htons( data - buf );
347 memcpy(nameoff, &ashort, sizeof( ashort ));
348 if ((aint = strlen( path )) > MACFILELEN)
351 memcpy(data, path, aint );
355 ad_close( adp, ADFLAGS_HF );
357 *buflen = data - buf;
360 LOG(log_info, logtype_default, "end getfilparams:");
366 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
369 int ibuflen, *rbuflen;
372 struct adouble ad, *adp;
377 int creatf, did, openf, retvalue = AFP_OK;
381 #endif /* FORCE_UIDGID */
384 LOG(log_info, logtype_default, "begin afp_createfile:");
389 creatf = (unsigned char) *ibuf++;
391 memcpy(&vid, ibuf, sizeof( vid ));
392 ibuf += sizeof( vid );
394 if (( vol = getvolbyvid( vid )) == NULL ) {
395 return( AFPERR_PARAM );
398 if (vol->v_flags & AFPVOL_RO)
401 memcpy(&did, ibuf, sizeof( did));
402 ibuf += sizeof( did );
404 if (( dir = dirsearch( vol, did )) == NULL ) {
405 return( AFPERR_NOOBJ );
408 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
409 return( AFPERR_NOOBJ );
412 if (!wincheck(vol, path))
415 upath = mtoupath(vol, path);
417 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
420 if (!validupath(vol, upath))
423 /* check for vetoed filenames */
424 if (veto_file(vol->v_veto, upath))
427 if ((of = of_findname(vol, curdir, path))) {
430 memset(&ad, 0, sizeof(ad));
434 /* on a hard create, fail if file exists and is open */
435 if ((stat(upath, &st) == 0) && of)
437 openf = O_RDWR|O_CREAT|O_TRUNC;
439 openf = O_RDWR|O_CREAT|O_EXCL;
444 /* preserve current euid, egid */
445 save_uidgid ( uidgid );
447 /* perform all switching of users */
450 #endif /* FORCE_UIDGID */
452 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
453 openf, 0666, adp) < 0 ) {
457 /* bring everything back to old euid, egid */
458 restore_uidgid ( uidgid );
459 #endif /* FORCE_UIDGID */
460 return( AFPERR_EXIST );
463 /* bring everything back to old euid, egid */
464 restore_uidgid ( uidgid );
465 #endif /* FORCE_UIDGID */
466 return( AFPERR_ACCESS );
468 /* on noadouble volumes, just creating the data fork is ok */
469 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
470 goto createfile_done;
474 /* bring everything back to old euid, egid */
475 restore_uidgid ( uidgid );
476 #endif /* FORCE_UIDGID */
477 return( AFPERR_PARAM );
481 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
482 memcpy(ad_entry( adp, ADEID_NAME ), path,
483 ad_getentrylen( adp, ADEID_NAME ));
484 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
485 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
490 if (vol->v_flags & AFPVOL_DROPBOX) {
491 retvalue = matchfile2dirperms(upath, vol, did);
493 #endif /* DROPKLUDGE */
495 setvoltime(obj, vol );
498 LOG(log_info, logtype_default, "end afp_createfile");
502 /* bring everything back to old euid, egid */
503 restore_uidgid ( uidgid );
504 #endif /* FORCE_UIDGID */
509 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
512 int ibuflen, *rbuflen;
518 u_int16_t vid, bitmap;
521 LOG(log_info, logtype_default, "begin afp_setfilparams:");
527 memcpy(&vid, ibuf, sizeof( vid ));
528 ibuf += sizeof( vid );
529 if (( vol = getvolbyvid( vid )) == NULL ) {
530 return( AFPERR_PARAM );
533 if (vol->v_flags & AFPVOL_RO)
536 memcpy(&did, ibuf, sizeof( did ));
537 ibuf += sizeof( did );
538 if (( dir = dirsearch( vol, did )) == NULL ) {
539 return( AFPERR_NOOBJ );
542 memcpy(&bitmap, ibuf, sizeof( bitmap ));
543 bitmap = ntohs( bitmap );
544 ibuf += sizeof( bitmap );
546 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
547 return( AFPERR_NOOBJ );
550 if ((u_long)ibuf & 1 ) {
554 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
555 setvoltime(obj, vol );
559 LOG(log_info, logtype_default, "end afp_setfilparams:");
566 int setfilparams(struct vol *vol,
567 char *path, u_int16_t bitmap, char *buf )
569 struct adouble ad, *adp;
572 int bit = 0, isad = 1, err = AFP_OK;
574 u_char achar, *fdType, xyy[4];
575 u_int16_t ashort, bshort;
582 uidgid = malloc(sizeof(uidgidset));
583 #endif /* FORCE_UIDGID */
586 LOG(log_info, logtype_default, "begin setfilparams:");
589 upath = mtoupath(vol, path);
590 if ((of = of_findname(vol, curdir, path))) {
593 memset(&ad, 0, sizeof(ad));
598 save_uidgid ( uidgid );
600 #endif /* FORCE_UIDGID */
602 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
603 O_RDWR|O_CREAT, 0666, adp) < 0) {
604 /* for some things, we don't need an adouble header */
605 if (bitmap & ~(1<<FILPBIT_MDATE)) {
607 restore_uidgid ( uidgid );
608 #endif /* FORCE_UIDGID */
609 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
612 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
613 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
614 memcpy(ad_entry( adp, ADEID_NAME ), path,
615 ad_getentrylen( adp, ADEID_NAME ));
618 while ( bitmap != 0 ) {
619 while (( bitmap & 1 ) == 0 ) {
626 memcpy(&ashort, buf, sizeof( ashort ));
627 ad_getattr(adp, &bshort);
628 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
629 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
633 ad_setattr(adp, bshort);
634 buf += sizeof( ashort );
638 memcpy(&aint, buf, sizeof(aint));
639 ad_setdate(adp, AD_DATE_CREATE, aint);
640 buf += sizeof( aint );
644 memcpy(&aint, buf, sizeof( aint ));
646 ad_setdate(adp, AD_DATE_MODIFY, aint);
647 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
649 buf += sizeof( aint );
653 memcpy(&aint, buf, sizeof(aint));
654 ad_setdate(adp, AD_DATE_BACKUP, aint);
655 buf += sizeof( aint );
659 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
660 && (em = getextmap( path )) &&
661 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
662 (memcmp(buf + 4, em->em_creator,
663 sizeof( em->em_creator )) == 0)) {
664 memcpy(buf, ufinderi, 8 );
666 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
670 /* Client needs to set the ProDOS file info for this file.
671 Use defined strings for the simple cases, and convert
672 all else into pXYY per Inside Appletalk. Always set
673 the creator as "pdos". <shirsch@ibm.net> */
674 case FILPBIT_PDINFO :
677 memcpy(&ashort, buf, sizeof( ashort ));
678 ashort = ntohs( ashort );
681 switch ( (unsigned int) achar )
684 fdType = ( u_char *) "TEXT";
688 fdType = ( u_char *) "PSYS";
692 fdType = ( u_char *) "PS16";
696 fdType = ( u_char *) "BINA";
700 xyy[0] = ( u_char ) 'p';
702 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
703 xyy[3] = ( u_char ) ashort & 0xff;
708 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
709 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
715 goto setfilparam_done;
724 ad_flush( adp, ADFLAGS_HF );
725 ad_close( adp, ADFLAGS_HF );
728 restore_uidgid ( uidgid );
729 #endif /* FORCE_UIDGID */
734 LOG(log_info, logtype_default, "end setfilparams:");
741 * renamefile and copyfile take the old and new unix pathnames
742 * and the new mac name.
743 * NOTE: if we have to copy a file instead of renaming it, locks
746 int renamefile(src, dst, newname, noadouble )
747 char *src, *dst, *newname;
751 char adsrc[ MAXPATHLEN + 1];
755 * Note that this is only checking the existance of the data file,
756 * not the header file. The thinking is that if the data file doesn't
757 * exist, but the header file does, the right thing to do is remove
758 * the data file silently.
761 /* existence check moved to afp_moveandrename */
764 LOG(log_info, logtype_default, "begin renamefile:");
767 if ( rename( src, dst ) < 0 ) {
770 return( AFPERR_NOOBJ );
773 return( AFPERR_ACCESS );
776 case EXDEV : /* Cross device move -- try copy */
777 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
781 return deletefile( src );
783 return( AFPERR_PARAM );
787 strcpy( adsrc, ad_path( src, 0 ));
790 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
795 /* check for a source appledouble header. if it exists, make
796 * a dest appledouble directory and do the rename again. */
797 memset(&ad, 0, sizeof(ad));
798 if (rc || stat(adsrc, &st) ||
799 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
802 ad_close(&ad, ADFLAGS_HF);
806 return( AFPERR_ACCESS );
810 return( AFPERR_PARAM );
814 memset(&ad, 0, sizeof(ad));
815 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
818 return( AFPERR_NOOBJ );
820 return( AFPERR_ACCESS );
824 return( AFPERR_PARAM );
828 len = strlen( newname );
829 ad_setentrylen( &ad, ADEID_NAME, len );
830 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
831 ad_flush( &ad, ADFLAGS_HF );
832 ad_close( &ad, ADFLAGS_HF );
835 LOG(log_info, logtype_default, "end renamefile:");
841 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
844 int ibuflen, *rbuflen;
848 char *newname, *path, *p;
849 u_int32_t sdid, ddid;
850 int plen, err, retvalue = AFP_OK;
851 u_int16_t svid, dvid;
854 LOG(log_info, logtype_default, "begin afp_copyfile:");
860 memcpy(&svid, ibuf, sizeof( svid ));
861 ibuf += sizeof( svid );
862 if (( vol = getvolbyvid( svid )) == NULL ) {
863 return( AFPERR_PARAM );
866 memcpy(&sdid, ibuf, sizeof( sdid ));
867 ibuf += sizeof( sdid );
868 if (( dir = dirsearch( vol, sdid )) == NULL ) {
869 return( AFPERR_PARAM );
872 memcpy(&dvid, ibuf, sizeof( dvid ));
873 ibuf += sizeof( dvid );
874 memcpy(&ddid, ibuf, sizeof( ddid ));
875 ibuf += sizeof( ddid );
877 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
878 return( AFPERR_NOOBJ );
880 if ( *path == '\0' ) {
881 return( AFPERR_BADTYPE );
884 /* don't allow copies when the file is open.
885 * XXX: the spec only calls for read/deny write access.
886 * however, copyfile doesn't have any of that info,
887 * and locks need to stay coherent. as a result,
888 * we just balk if the file is opened already. */
889 if (of_findname(vol, curdir, path))
890 return AFPERR_DENYCONF;
892 newname = obj->newtmp;
893 strcpy( newname, path );
895 p = ctoupath( vol, curdir, newname );
897 if (( vol = getvolbyvid( dvid )) == NULL ) {
898 return( AFPERR_PARAM );
901 if (vol->v_flags & AFPVOL_RO)
904 if (( dir = dirsearch( vol, ddid )) == NULL ) {
905 return( AFPERR_PARAM );
908 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
909 return( AFPERR_NOOBJ );
911 if ( *path != '\0' ) {
912 return( AFPERR_BADTYPE );
915 /* one of the handful of places that knows about the path type */
916 if ( *ibuf++ != 2 ) {
917 return( AFPERR_PARAM );
919 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
920 strncpy( newname, ibuf, plen );
921 newname[ plen ] = '\0';
924 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
925 vol_noadouble(vol))) < 0 ) {
929 setvoltime(obj, vol );
932 if (vol->v_flags & AFPVOL_DROPBOX) {
933 retvalue=matchfile2dirperms(newname, vol, sdid);
935 #endif /* DROPKLUDGE */
938 LOG(log_info, logtype_default, "end afp_copyfile:");
945 static __inline__ int copy_all(const int dfd, const void *buf,
951 LOG(log_info, logtype_default, "begin copy_all:");
955 if ((cc = write(dfd, buf, buflen)) < 0) {
973 LOG(log_info, logtype_default, "end copy_all:");
979 /* XXX: this needs to use ad_open and ad_lock. so, we need to
980 * pass in vol and path */
981 int copyfile(src, dst, newname, noadouble )
982 char *src, *dst, *newname;
988 int sfd, dfd, len, err = AFP_OK;
992 LOG(log_info, logtype_default, "begin copyfile:");
996 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
999 break; /* just copy the data fork */
1001 return( AFPERR_ACCESS );
1003 return( AFPERR_PARAM );
1006 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1007 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1011 return( AFPERR_NOOBJ );
1013 return( AFPERR_ACCESS );
1015 return AFPERR_VLOCK;
1017 return( AFPERR_PARAM );
1022 #ifdef SENDFILE_FLAVOR_LINUX
1023 if (fstat(sfd, &st) == 0) {
1024 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1038 goto copyheader_done;
1040 #endif /* SENDFILE_FLAVOR_LINUX */
1042 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1049 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1057 unlink(ad_path(dst, ADFLAGS_HF));
1063 /* data fork copying */
1064 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1067 return( AFPERR_NOOBJ );
1069 return( AFPERR_ACCESS );
1071 return( AFPERR_PARAM );
1075 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1079 return( AFPERR_NOOBJ );
1081 return( AFPERR_ACCESS );
1083 return AFPERR_VLOCK;
1085 return( AFPERR_PARAM );
1089 #ifdef SENDFILE_FLAVOR_LINUX
1090 if (fstat(sfd, &st) == 0) {
1091 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1104 #endif /* SENDFILE_FLAVOR_LINUX */
1107 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1115 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1124 unlink(ad_path(dst, ADFLAGS_HF));
1130 memset(&ad, 0, sizeof(ad));
1131 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1135 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1137 return( AFPERR_ACCESS );
1139 return AFPERR_VLOCK;
1141 return( AFPERR_PARAM );
1145 len = strlen( newname );
1146 ad_setentrylen( &ad, ADEID_NAME, len );
1147 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1148 ad_flush( &ad, ADFLAGS_HF );
1149 ad_close( &ad, ADFLAGS_HF );
1153 LOG(log_info, logtype_default, "end copyfile:");
1160 int deletefile( file )
1164 int adflags, err = AFP_OK;
1165 int locktype = ADLOCK_WR;
1166 int openmode = O_RDWR;
1169 LOG(log_info, logtype_default, "begin deletefile:");
1174 * If can't open read/write then try again read-only. If it's open
1175 * read-only, we must do a read lock instead of a write lock.
1177 /* try to open both at once */
1178 adflags = ADFLAGS_DF|ADFLAGS_HF;
1179 memset(&ad, 0, sizeof(ad));
1180 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1183 adflags = ADFLAGS_DF;
1184 /* that failed. now try to open just the data fork */
1185 memset(&ad, 0, sizeof(ad));
1186 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1189 return AFPERR_NOOBJ;
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;
1207 if(openmode == O_RDWR) {
1208 openmode = O_RDONLY;
1209 locktype = ADLOCK_RD;
1212 return AFPERR_ACCESS;
1215 return AFPERR_VLOCK;
1217 return( AFPERR_PARAM );
1220 break; /* from the while */
1223 if ((adflags & ADFLAGS_HF) &&
1224 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1225 ad_close( &ad, adflags );
1226 return( AFPERR_BUSY );
1229 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1234 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1238 err = AFPERR_ACCESS;
1251 if ( unlink( file ) < 0 ) {
1255 err = AFPERR_ACCESS;
1269 if (adflags & ADFLAGS_HF)
1270 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1271 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1272 ad_close( &ad, adflags );
1275 LOG(log_info, logtype_default, "end deletefile:");
1283 /* return a file id */
1284 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1287 int ibuflen, *rbuflen;
1299 LOG(log_info, logtype_default, "begin afp_createid:");
1305 memcpy(&vid, ibuf, sizeof(vid));
1306 ibuf += sizeof(vid);
1308 if (( vol = getvolbyvid( vid )) == NULL ) {
1309 return( AFPERR_PARAM);
1312 if (vol->v_flags & AFPVOL_RO)
1313 return AFPERR_VLOCK;
1315 memcpy(&did, ibuf, sizeof( did ));
1316 ibuf += sizeof(did);
1318 if (( dir = dirsearch( vol, did )) == NULL ) {
1319 return( AFPERR_PARAM );
1322 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1323 return( AFPERR_PARAM );
1326 if ( *path == '\0' ) {
1327 return( AFPERR_BADTYPE );
1330 upath = mtoupath(vol, path);
1331 if (stat(upath, &st) < 0) {
1335 return AFPERR_ACCESS;
1337 return AFPERR_NOOBJ;
1339 return AFPERR_PARAM;
1343 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1344 memcpy(rbuf, &id, sizeof(id));
1345 *rbuflen = sizeof(id);
1346 return AFPERR_EXISTID;
1349 #if AD_VERSION > AD_VERSION1
1350 memset(&ad, 0, sizeof(ad));
1351 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1352 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1353 ad_close(&ad, ADFLAGS_HF);
1355 #endif /* AD_VERSION > AD_VERSION1 */
1357 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1358 memcpy(rbuf, &id, sizeof(id));
1359 *rbuflen = sizeof(id);
1364 LOG(log_info, logtype_default, "ending afp_createid...:");
1369 return AFPERR_VLOCK;
1373 return AFPERR_ACCESS;
1376 LOG(log_error, logtype_default, "afp_createid: cnid_add: %m");
1377 return AFPERR_PARAM;
1381 /* resolve a file id */
1382 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1385 int ibuflen, *rbuflen;
1393 u_int16_t vid, bitmap;
1396 LOG(log_info, logtype_default, "begin afp_resolveid:");
1402 memcpy(&vid, ibuf, sizeof(vid));
1403 ibuf += sizeof(vid);
1405 if (( vol = getvolbyvid( vid )) == NULL ) {
1406 return( AFPERR_PARAM);
1409 memcpy(&id, ibuf, sizeof( id ));
1412 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1413 return AFPERR_BADID;
1416 if (( dir = dirsearch( vol, id )) == NULL ) {
1417 return( AFPERR_PARAM );
1420 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1424 return AFPERR_ACCESS;
1428 return AFPERR_PARAM;
1432 /* directories are bad */
1433 if (S_ISDIR(st.st_mode))
1434 return AFPERR_BADTYPE;
1436 memcpy(&bitmap, ibuf, sizeof(bitmap));
1437 bitmap = ntohs( bitmap );
1439 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1440 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1443 *rbuflen = buflen + sizeof(bitmap);
1444 memcpy(rbuf, ibuf, sizeof(bitmap));
1447 LOG(log_info, logtype_default, "end afp_resolveid:");
1453 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1456 int ibuflen, *rbuflen;
1467 LOG(log_info, logtype_default, "begin afp_deleteid:");
1473 memcpy(&vid, ibuf, sizeof(vid));
1474 ibuf += sizeof(vid);
1476 if (( vol = getvolbyvid( vid )) == NULL ) {
1477 return( AFPERR_PARAM);
1480 if (vol->v_flags & AFPVOL_RO)
1481 return AFPERR_VLOCK;
1483 memcpy(&id, ibuf, sizeof( id ));
1486 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1490 if (( dir = dirsearch( vol, id )) == NULL ) {
1491 return( AFPERR_PARAM );
1495 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1499 return AFPERR_ACCESS;
1501 /* still try to delete the id */
1505 return AFPERR_PARAM;
1509 /* directories are bad */
1510 if (S_ISDIR(st.st_mode))
1511 return AFPERR_BADTYPE;
1513 if (cnid_delete(vol->v_db, id)) {
1516 return AFPERR_VLOCK;
1519 return AFPERR_ACCESS;
1521 return AFPERR_PARAM;
1526 LOG(log_info, logtype_default, "end afp_deleteid:");
1531 #endif /* CNID_DB */
1533 #define APPLETEMP ".AppleTempXXXXXX"
1535 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1538 int ibuflen, *rbuflen;
1540 struct stat srcst, destst;
1542 struct dir *dir, *sdir;
1543 char *spath, temp[17], *path, *p;
1544 char *supath, *upath;
1548 #endif /* CNID_DB */
1553 LOG(log_info, logtype_default, "begin afp_exchangefiles:");
1559 memcpy(&vid, ibuf, sizeof(vid));
1560 ibuf += sizeof(vid);
1562 if (( vol = getvolbyvid( vid )) == NULL ) {
1563 return( AFPERR_PARAM);
1566 if (vol->v_flags & AFPVOL_RO)
1567 return AFPERR_VLOCK;
1569 /* source and destination dids */
1570 memcpy(&sid, ibuf, sizeof(sid));
1571 ibuf += sizeof(sid);
1572 memcpy(&did, ibuf, sizeof(did));
1573 ibuf += sizeof(did);
1576 if ((dir = dirsearch( vol, sid )) == NULL ) {
1577 return( AFPERR_PARAM );
1580 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1581 return( AFPERR_PARAM );
1584 if ( *path == '\0' ) {
1585 return( AFPERR_BADTYPE );
1588 upath = mtoupath(vol, path);
1589 if (stat(upath, &srcst) < 0) {
1595 return AFPERR_ACCESS;
1597 return AFPERR_PARAM;
1601 /* save some stuff */
1603 spath = obj->oldtmp;
1604 supath = obj->newtmp;
1605 strcpy(spath, path);
1606 strcpy(supath, upath); /* this is for the cnid changing */
1607 p = ctoupath( vol, sdir, spath);
1609 /* look for the source cnid. if it doesn't exist, don't worry about
1612 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1613 slen = strlen(supath));
1614 #endif /* CNID_DB */
1616 if (( dir = dirsearch( vol, did )) == NULL ) {
1617 return( AFPERR_PARAM );
1620 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1621 return( AFPERR_PARAM );
1624 if ( *path == '\0' ) {
1625 return( AFPERR_BADTYPE );
1628 /* FPExchangeFiles is the only call that can return the SameObj
1630 if ((curdir == sdir) && strcmp(spath, path) == 0)
1631 return AFPERR_SAMEOBJ;
1633 upath = mtoupath(vol, path);
1634 if (stat(upath, &destst) < 0) {
1640 return AFPERR_ACCESS;
1642 return AFPERR_PARAM;
1647 /* look for destination id. */
1648 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1649 dlen = strlen(upath));
1650 #endif /* CNID_DB */
1652 /* construct a temp name.
1653 * NOTE: the temp file will be in the dest file's directory. it
1654 * will also be inaccessible from AFP. */
1655 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1659 /* now, quickly rename the file. we error if we can't. */
1660 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1661 goto err_exchangefile;
1662 of_rename(vol, sdir, spath, curdir, temp);
1664 /* rename destination to source */
1665 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1666 goto err_src_to_tmp;
1667 of_rename(vol, curdir, path, sdir, spath);
1669 /* rename temp to destination */
1670 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1671 goto err_dest_to_src;
1672 of_rename(vol, curdir, temp, curdir, path);
1675 /* id's need switching. src -> dest and dest -> src. */
1676 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1677 upath, dlen) < 0)) {
1681 err = AFPERR_ACCESS;
1686 goto err_temp_to_dest;
1689 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1690 supath, slen) < 0)) {
1694 err = AFPERR_ACCESS;
1701 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1702 goto err_temp_to_dest;
1704 #endif /* CNID_DB */
1707 LOG(log_info, logtype_default, "ending afp_exchangefiles:");
1713 /* all this stuff is so that we can unwind a failed operation
1716 /* rename dest to temp */
1717 renamefile(upath, temp, temp, vol_noadouble(vol));
1718 of_rename(vol, curdir, upath, curdir, temp);
1721 /* rename source back to dest */
1722 renamefile(p, upath, path, vol_noadouble(vol));
1723 of_rename(vol, sdir, spath, curdir, path);
1726 /* rename temp back to source */
1727 renamefile(temp, p, spath, vol_noadouble(vol));
1728 of_rename(vol, curdir, temp, sdir, spath);