--- libeio/eio.c 2012/04/24 18:47:50 1.120 +++ libeio/eio.c 2013/02/18 03:16:30 1.128 @@ -6,14 +6,14 @@ * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -134,6 +134,41 @@ #define statvfs(path,buf) EIO_ENOSYS () #define fstatvfs(fd,buf) EIO_ENOSYS () + #define pread(fd,buf,count,offset) eio__pread (fd, buf, count, offset) + #define pwrite(fd,buf,count,offset) eio__pwrite (fd, buf, count, offset) + + #if __GNUC__ + typedef long long eio_off_t; /* signed for compatibility to msvc */ + #else + typedef __int64 eio_off_t; /* unsigned not supported by msvc */ + #endif + + static eio_ssize_t + eio__pread (int fd, void *buf, eio_ssize_t count, eio_off_t offset) + { + OVERLAPPED o = { 0 }; + DWORD got; + + o.Offset = offset; + o.OffsetHigh = offset >> 32; + + return ReadFile ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd), buf, count, &got, &o) + ? got : -1; + } + + static eio_ssize_t + eio__pwrite (int fd, void *buf, eio_ssize_t count, eio_off_t offset) + { + OVERLAPPED o = { 0 }; + DWORD got; + + o.Offset = offset; + o.OffsetHigh = offset >> 32; + + return WriteFile ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd), buf, count, &got, &o) + ? got : -1; + } + /* rename() uses MoveFile, which fails to overwrite */ #define rename(old,neu) eio__rename (old, neu) @@ -198,11 +233,19 @@ #include #include - #include #include #include #include + #ifdef ANDROID + #include + #define statvfs statfs + #define fstatvfs fstatfs + #include /* supposedly limits.h does #define PAGESIZE PAGESIZE */ + #else + #include + #endif + #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES #include #endif @@ -283,7 +326,7 @@ /* buffer size for various temporary buffers */ #define EIO_BUFSIZE 65536 -#define dBUF \ +#define dBUF \ char *eio_buf = malloc (EIO_BUFSIZE); \ errno = ENOMEM; \ if (!eio_buf) \ @@ -381,15 +424,6 @@ static xmutex_t reqlock; static xcond_t reqwait; -#if !HAVE_PREADWRITE -/* - * make our pread/pwrite emulation safe against themselves, but not against - * normal read/write by using a mutex. slows down execution a lot, - * but that's your problem, not mine. - */ -static xmutex_t preadwritelock; -#endif - typedef struct etp_worker { struct tmpbuf tmpbuf; @@ -578,7 +612,7 @@ X_LOCK (wrklock); - if (thread_create (&wrk->tid, etp_proc, (void *)wrk)) + if (xthread_create (&wrk->tid, etp_proc, (void *)wrk)) { wrk->prev = &wrk_first; wrk->next = wrk_first.next; @@ -945,45 +979,6 @@ /*****************************************************************************/ /* work around various missing functions */ -#if !HAVE_PREADWRITE -# undef pread -# undef pwrite -# define pread eio__pread -# define pwrite eio__pwrite - -static eio_ssize_t -eio__pread (int fd, void *buf, size_t count, off_t offset) -{ - eio_ssize_t res; - off_t ooffset; - - X_LOCK (preadwritelock); - ooffset = lseek (fd, 0, SEEK_CUR); - lseek (fd, offset, SEEK_SET); - res = read (fd, buf, count); - lseek (fd, ooffset, SEEK_SET); - X_UNLOCK (preadwritelock); - - return res; -} - -static eio_ssize_t -eio__pwrite (int fd, void *buf, size_t count, off_t offset) -{ - eio_ssize_t res; - off_t ooffset; - - X_LOCK (preadwritelock); - ooffset = lseek (fd, 0, SEEK_CUR); - lseek (fd, offset, SEEK_SET); - res = write (fd, buf, count); - lseek (fd, ooffset, SEEK_SET); - X_UNLOCK (preadwritelock); - - return res; -} -#endif - #ifndef HAVE_UTIMES # undef utimes @@ -1431,15 +1426,14 @@ { sprintf (tmp1, "/proc/self/fd/%d", fd); req->result = readlink (tmp1, res, PATH_MAX); - close (fd); - /* here we should probably stat the open file and the disk file, to make sure they still match */ + close (fd); if (req->result > 0) goto done; } else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO) - return; + return -1; } #endif #endif @@ -1933,31 +1927,31 @@ #endif #ifdef DT_CHR case DT_CHR: ent->type = EIO_DT_CHR; break; - #endif + #endif #ifdef DT_MPC case DT_MPC: ent->type = EIO_DT_MPC; break; - #endif + #endif #ifdef DT_DIR case DT_DIR: ent->type = EIO_DT_DIR; break; - #endif + #endif #ifdef DT_NAM case DT_NAM: ent->type = EIO_DT_NAM; break; - #endif + #endif #ifdef DT_BLK case DT_BLK: ent->type = EIO_DT_BLK; break; - #endif + #endif #ifdef DT_MPB case DT_MPB: ent->type = EIO_DT_MPB; break; - #endif + #endif #ifdef DT_REG case DT_REG: ent->type = EIO_DT_REG; break; - #endif + #endif #ifdef DT_NWK case DT_NWK: ent->type = EIO_DT_NWK; break; - #endif + #endif #ifdef DT_CMP case DT_CMP: ent->type = EIO_DT_CMP; break; - #endif + #endif #ifdef DT_LNK case DT_LNK: ent->type = EIO_DT_LNK; break; #endif @@ -2242,6 +2236,8 @@ X_LOCK (wrklock); etp_worker_free (self); X_UNLOCK (wrklock); + + return 0; } /*****************************************************************************/ @@ -2249,10 +2245,6 @@ int ecb_cold eio_init (void (*want_poll)(void), void (*done_poll)(void)) { -#if !HAVE_PREADWRITE - X_MUTEX_CREATE (preadwritelock); -#endif - return etp_init (want_poll, done_poll); } @@ -2262,7 +2254,7 @@ free (req); } -#define REQ(rtype) \ +#define REQ(rtype) \ eio_req *req; \ \ req = (eio_req *)calloc (1, sizeof *req); \ @@ -2286,6 +2278,8 @@ return 0; \ } +#define SINGLEDOT(ptr) (0[(char *)(ptr)] == '.' && !1[(char *)(ptr)]) + static void eio_execute (etp_worker *self, eio_req *req) { @@ -2350,9 +2344,15 @@ case EIO_OPEN: req->result = openat (dirfd, req->ptr1, req->int1, (mode_t)req->int2); break; case EIO_UNLINK: req->result = unlinkat (dirfd, req->ptr1, 0); break; - case EIO_RMDIR: req->result = unlinkat (dirfd, req->ptr1, AT_REMOVEDIR); break; + case EIO_RMDIR: /* complications arise because "." cannot be removed, so we might have to expand */ + req->result = req->wd && SINGLEDOT (req->ptr1) + ? rmdir (req->wd->str) + : unlinkat (dirfd, req->ptr1, AT_REMOVEDIR); break; case EIO_MKDIR: req->result = mkdirat (dirfd, req->ptr1, (mode_t)req->int2); break; - case EIO_RENAME: req->result = renameat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2); break; + case EIO_RENAME: /* complications arise because "." cannot be renamed, so we might have to expand */ + req->result = req->wd && SINGLEDOT (req->ptr1) + ? rename (req->wd->str, req->ptr2) + : renameat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2); break; case EIO_LINK: req->result = linkat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2, 0); break; case EIO_SYMLINK: req->result = symlinkat (req->ptr1, dirfd, req->ptr2); break; case EIO_MKNOD: req->result = mknodat (dirfd, req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break;