📄 fhandler_disk_file.cc
字号:
* This shouldn't break many apps but denying all locking * would. * For now just convert to Win32 locks and hope for the best. */intfhandler_disk_file::lock (int cmd, struct flock *fl){ __off64_t win32_start; int win32_len; DWORD win32_upper; __off64_t startpos; /* * We don't do getlck calls yet. */ if (cmd == F_GETLK) { set_errno (ENOSYS); return -1; } /* * Calculate where in the file to start from, * then adjust this by fl->l_start. */ switch (fl->l_whence) { case SEEK_SET: startpos = 0; break; case SEEK_CUR: if ((startpos = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK) return -1; break; case SEEK_END: { BY_HANDLE_FILE_INFORMATION finfo; if (GetFileInformationByHandle (get_handle (), &finfo) == 0) { __seterrno (); return -1; } startpos = ((__off64_t)finfo.nFileSizeHigh << 32) + finfo.nFileSizeLow; break; } default: set_errno (EINVAL); return -1; } /* * Now the fun starts. Adjust the start and length * fields until they make sense. */ win32_start = startpos + fl->l_start; if (fl->l_len < 0) { win32_start -= fl->l_len; win32_len = -fl->l_len; } else win32_len = fl->l_len; if (win32_start < 0) { /* watch the signs! */ win32_len -= -win32_start; if (win32_len <= 0) { /* Failure ! */ set_errno (EINVAL); return -1; } win32_start = 0; } /* * Special case if len == 0 for POSIX means lock * to the end of the entire file (and all future extensions). */ if (win32_len == 0) { win32_len = 0xffffffff; win32_upper = wincap.lock_file_highword (); } else win32_upper = 0; BOOL res; if (wincap.has_lock_file_ex ()) { DWORD lock_flags = (cmd == F_SETLK) ? LOCKFILE_FAIL_IMMEDIATELY : 0; lock_flags |= (fl->l_type == F_WRLCK) ? LOCKFILE_EXCLUSIVE_LOCK : 0; OVERLAPPED ov; ov.Internal = 0; ov.InternalHigh = 0; ov.Offset = (DWORD)win32_start; ov.OffsetHigh = 0; ov.hEvent = (HANDLE) 0; if (fl->l_type == F_UNLCK) { res = UnlockFileEx (get_handle (), 0, (DWORD)win32_len, win32_upper, &ov); } else { res = LockFileEx (get_handle (), lock_flags, 0, (DWORD)win32_len, win32_upper, &ov); /* Deal with the fail immediately case. */ /* * FIXME !! I think this is the right error to check for * but I must admit I haven't checked.... */ if ((res == 0) && (lock_flags & LOCKFILE_FAIL_IMMEDIATELY) && (GetLastError () == ERROR_LOCK_FAILED)) { set_errno (EAGAIN); return -1; } } } else { /* Windows 95 -- use primitive lock call */ if (fl->l_type == F_UNLCK) res = UnlockFile (get_handle (), (DWORD)win32_start, 0, (DWORD)win32_len, win32_upper); else res = LockFile (get_handle (), (DWORD)win32_start, 0, (DWORD)win32_len, win32_upper); } if (res == 0) { __seterrno (); return -1; } return 0;}DIR *fhandler_disk_file::opendir (path_conv& real_name){ DIR *dir; DIR *res = NULL; size_t len; if (!real_name.isdir ()) set_errno (ENOTDIR); else if ((len = strlen (real_name))> MAX_PATH - 3) set_errno (ENAMETOOLONG); else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL) set_errno (ENOMEM); else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL) { free (dir); set_errno (ENOMEM); } else if ((dir->__d_dirent = (struct dirent *) malloc (sizeof (struct dirent))) == NULL) { free (dir->__d_dirname); free (dir); set_errno (ENOMEM); } else { strcpy (dir->__d_dirname, real_name.get_win32 ()); dir->__d_dirent->d_version = __DIRENT_VERSION; cygheap_fdnew fd; fd = this; fd->set_nohandle (true); dir->__d_dirent->d_fd = fd; dir->__d_u.__d_data.__fh = this; /* FindFirstFile doesn't seem to like duplicate /'s. */ len = strlen (dir->__d_dirname); if (len == 0 || SLASH_P (dir->__d_dirname[len - 1])) strcat (dir->__d_dirname, "*"); else strcat (dir->__d_dirname, "\\*"); /**/ dir->__d_cookie = __DIRENT_COOKIE; dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; dir->__d_position = 0; dir->__d_dirhash = get_namehash (); res = dir; } syscall_printf ("%p = opendir (%s)", res, get_name ()); return res;}struct dirent *fhandler_disk_file::readdir (DIR *dir){ WIN32_FIND_DATA buf; HANDLE handle; struct dirent *res = NULL; if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0) { handle = FindFirstFileA (dir->__d_dirname, &buf); DWORD lasterr = GetLastError (); dir->__d_u.__d_data.__handle = handle; if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { seterrno_from_win_error (__FILE__, __LINE__, lasterr); return res; } } else if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) { return res; } else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf)) { DWORD lasterr = GetLastError (); (void) FindClose (dir->__d_u.__d_data.__handle); dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; /* POSIX says you shouldn't set errno when readdir can't find any more files; so, if another error we leave it set. */ if (lasterr != ERROR_NO_MORE_FILES) seterrno_from_win_error (__FILE__, __LINE__, lasterr); syscall_printf ("%p = readdir (%p)", res, dir); return res; } /* We get here if `buf' contains valid data. */ strcpy (dir->__d_dirent->d_name, buf.cFileName); /* Check for Windows shortcut. If it's a Cygwin or U/WIN symlink, drop the .lnk suffix. */ if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { char *c = dir->__d_dirent->d_name; int len = strlen (c); if (strcasematch (c + len - 4, ".lnk")) { char fbuf[MAX_PATH + 1]; strcpy (fbuf, dir->__d_dirname); strcpy (fbuf + strlen (fbuf) - 1, dir->__d_dirent->d_name); path_conv fpath (fbuf, PC_SYM_NOFOLLOW); if (fpath.issymlink ()) c[len - 4] = '\0'; } } dir->__d_position++; res = dir->__d_dirent; syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, buf.cFileName); return res;}__off64_tfhandler_disk_file::telldir (DIR *dir){ return dir->__d_position;}voidfhandler_disk_file::seekdir (DIR *dir, __off64_t loc){ rewinddir (dir); while (loc > dir->__d_position) if (!readdir (dir)) break;}voidfhandler_disk_file::rewinddir (DIR *dir){ if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) { (void) FindClose (dir->__d_u.__d_data.__handle); dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; } dir->__d_position = 0;}intfhandler_disk_file::closedir (DIR *dir){ int res = 0; if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE && FindClose (dir->__d_u.__d_data.__handle) == 0) { __seterrno (); res = -1; } syscall_printf ("%d = closedir (%p)", res, dir); return 0;}fhandler_cygdrive::fhandler_cygdrive (int unit) : fhandler_disk_file (FH_CYGDRIVE), unit (unit), ndrives (0), pdrive (NULL){}#define DRVSZ sizeof ("x:\\")voidfhandler_cygdrive::set_drives (){ const int len = 1 + 26 * DRVSZ; char *p = (char *) crealloc ((void *) win32_path_name, sizeof (".") + sizeof ("..") + len); win32_path_name = pdrive = p; strcpy (p, "."); strcpy (p + sizeof ("."), ".."); p += sizeof (".") + sizeof (".."); ndrives = GetLogicalDriveStrings (len, p) / DRVSZ;}intfhandler_cygdrive::fstat (struct __stat64 *buf, path_conv *pc){ if (!iscygdrive_root ()) return fhandler_disk_file::fstat (buf, pc); buf->st_mode = S_IFDIR | 0555; if (!ndrives) set_drives (); buf->st_nlink = ndrives; return 0;}DIR *fhandler_cygdrive::opendir (path_conv& real_name){ DIR *dir; dir = fhandler_disk_file::opendir (real_name); if (dir && iscygdrive_root () && !ndrives) set_drives (); return dir;}struct dirent *fhandler_cygdrive::readdir (DIR *dir){ if (!iscygdrive_root ()) return fhandler_disk_file::readdir (dir); if (!pdrive || !*pdrive) { set_errno (ENMFILE); return NULL; } else if (dir->__d_position > 1 && GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES) { pdrive = strchr (pdrive, '\0') + 1; return readdir (dir); } else if (*pdrive == '.') strcpy (dir->__d_dirent->d_name, pdrive); else { *dir->__d_dirent->d_name = cyg_tolower (*pdrive); dir->__d_dirent->d_name[1] = '\0'; } dir->__d_position++; pdrive = strchr (pdrive, '\0') + 1; syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, dir->__d_dirent->d_name); return dir->__d_dirent;}__off64_tfhandler_cygdrive::telldir (DIR *dir){ return fhandler_disk_file::telldir (dir);}voidfhandler_cygdrive::seekdir (DIR *dir, __off64_t loc){ if (!iscygdrive_root ()) return fhandler_disk_file::seekdir (dir, loc); for (pdrive = win32_path_name, dir->__d_position = -1; *pdrive; pdrive = strchr (pdrive, '\0') + 1) if (++dir->__d_position >= loc) break; return;}voidfhandler_cygdrive::rewinddir (DIR *dir){ if (!iscygdrive_root ()) return fhandler_disk_file::rewinddir (dir); pdrive = win32_path_name; dir->__d_position = 0; return;}intfhandler_cygdrive::closedir (DIR *dir){ if (!iscygdrive_root ()) return fhandler_disk_file::closedir (dir); pdrive = win32_path_name; return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -