mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
ide: In Posix, ide now handles non-owned files and symlinks differently #230
git-svn-id: svn://ultimatepp.org/upp/trunk@6922 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
6b1c0d81ea
commit
d9fde3de2b
10 changed files with 148 additions and 61 deletions
|
|
@ -257,6 +257,7 @@ void BlockStream::OpenInit(dword mode, int64 _filesize) {
|
|||
if(!buffer)
|
||||
SetBufferSize(4096);
|
||||
if(mode == APPEND) SeekEnd();
|
||||
ClearError();
|
||||
}
|
||||
|
||||
// ---------------------------- File stream -----------------------------
|
||||
|
|
|
|||
|
|
@ -653,6 +653,17 @@ struct stat& FindFile::Stat() const {
|
|||
return statf;
|
||||
}
|
||||
|
||||
bool FindFile::CanMode(dword usr, dword grp, dword oth) const
|
||||
{
|
||||
const struct stat& s = Stat();
|
||||
dword mode = GetMode();
|
||||
static uid_t uid = getuid();
|
||||
static gid_t gid = getgid();
|
||||
return (mode & oth) ||
|
||||
(mode & grp) && gid == s.st_gid ||
|
||||
(mode & usr) && uid == s.st_uid;
|
||||
}
|
||||
|
||||
bool FindFile::IsSymLink() const
|
||||
{
|
||||
if(file) {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ class FindFile : NoCopy {
|
|||
String pattern;
|
||||
|
||||
struct stat &Stat() const;
|
||||
bool CanMode(dword usr, dword grp, dword oth) const;
|
||||
|
||||
public:
|
||||
bool Search(const char *name);
|
||||
|
|
@ -133,7 +134,14 @@ public:
|
|||
FileTime GetLastAccessTime() const { return Stat().st_atime; }
|
||||
FileTime GetLastWriteTime() const { return Stat().st_mtime; }
|
||||
|
||||
bool IsReadOnly() const { return !(GetMode() & (S_IWUSR|S_IWGRP|S_IWOTH)); }
|
||||
uid_t GetUid() { return Stat().st_uid; }
|
||||
gid_t GetGid() { return Stat().st_gid; }
|
||||
|
||||
bool CanRead() const { return CanMode(S_IRUSR, S_IRGRP, S_IROTH); }
|
||||
bool CanWrite() const { return CanMode(S_IWUSR, S_IWGRP, S_IWOTH); }
|
||||
bool CanExecute() const { return CanMode(S_IXUSR, S_IXGRP, S_IXOTH); }
|
||||
|
||||
bool IsReadOnly() const { return CanRead() && !CanWrite(); }
|
||||
|
||||
bool IsHidden() const { return *name == '.'; }
|
||||
bool IsDirectory() const { return S_ISDIR(GetMode()); }
|
||||
|
|
|
|||
|
|
@ -1089,6 +1089,7 @@ void CompareStream::Open(Stream& astream) {
|
|||
wrlim = buffer + 128;
|
||||
ptr = buffer;
|
||||
equal = true;
|
||||
ClearError();
|
||||
}
|
||||
|
||||
bool CompareStream::IsOpen() const {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,34 @@ with all filesystems.&]
|
|||
_[@(0.0.255) const]&]
|
||||
[s2;%% Returns the last time the entry was modified. Always works.&]
|
||||
[s3;%% &]
|
||||
[s4; &]
|
||||
[s5;:FindFile`:`:GetLastChangeTime`(`)const: uid`_t_[* GetUid]()&]
|
||||
[s6;%% `[POSIX`]&]
|
||||
[s2;%% Returns user ID of file.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:FindFile`:`:GetLastChangeTime`(`)const: gid`_t_[* GetGid]()&]
|
||||
[s6;%% `[POSIX`]&]
|
||||
[s2;%% Returns group ID of file.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [@(0.0.255) bool]_[* CanRead]()_[@(0.0.255) co
|
||||
nst]&]
|
||||
[s6;%% `[POSIX`]&]
|
||||
[s2;%% Returns true if current user can read the file.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [@(0.0.255) bool]_[* CanWrite]()_[@(0.0.255) c
|
||||
onst]&]
|
||||
[s6;%% `[POSIX`]&]
|
||||
[s2;%% Returns true if current user can write the file.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [@(0.0.255) bool]_[* CanExecute]()_[@(0.0.255) c
|
||||
onst]&]
|
||||
[s6;%% `[POSIX`]&]
|
||||
[s2;%% Returns true if current user can execute the file.&]
|
||||
[s3; &]
|
||||
[s4;%% &]
|
||||
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [_^FileTime^ FileTime]_[* GetLastChangeTime](
|
||||
)_[@(0.0.255) const]&]
|
||||
|
|
|
|||
|
|
@ -284,7 +284,8 @@ onst]&]
|
|||
[s7; [* Return value]-|Size of stream.&]
|
||||
[s3; &]
|
||||
[s4;%- &]
|
||||
[s5;K%- [@(0.0.255) virtual] [@(0.0.255) void]_[* SetSize]([_^int64^ int64]_[*@3 size])&]
|
||||
[s5;:Stream`:`:SetSize`(int64`):%- [@(0.0.255) virtual] [@(0.0.255) void]_[* SetSize]([_^int64^ i
|
||||
nt64]_[*@3 size])&]
|
||||
[s2; Alters the size of the stream.&]
|
||||
[s7; [%-*C@3 size]-|New size.&]
|
||||
[s3; &]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ LineEdit::LineEdit() {
|
|||
filter = NULL;
|
||||
showspaces = false;
|
||||
showlines = false;
|
||||
showreadonly = true;
|
||||
}
|
||||
|
||||
LineEdit::~LineEdit() {}
|
||||
|
|
@ -100,7 +101,7 @@ void LineEdit::Paint0(Draw& w) {
|
|||
if(w.IsPainting(0, y, sz.cx, fsz.cy)) {
|
||||
Highlight ih;
|
||||
ih.ink = color[IsShowEnabled() ? INK_NORMAL : INK_DISABLED];
|
||||
ih.paper = color[IsReadOnly() || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL];
|
||||
ih.paper = color[IsReadOnly() && showreadonly || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL];
|
||||
if(nobg)
|
||||
ih.paper = Null;
|
||||
ih.font = font;
|
||||
|
|
@ -221,7 +222,7 @@ void LineEdit::Paint0(Draw& w) {
|
|||
selh -= len + 1;
|
||||
pos += len + 1;
|
||||
}
|
||||
w.DrawRect(0, y, sz.cx, sz.cy - y, color[IsReadOnly() || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL]);
|
||||
w.DrawRect(0, y, sz.cx, sz.cy - y, color[IsReadOnly() && showreadonly || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL]);
|
||||
DrawTiles(w, DropCaret(), CtrlImg::checkers());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ protected:
|
|||
bool overwrite;
|
||||
bool showspaces;
|
||||
bool showlines;
|
||||
bool showreadonly;
|
||||
|
||||
void Paint0(Draw& w);
|
||||
|
||||
|
|
@ -362,6 +363,9 @@ public:
|
|||
LineEdit& NoCutLine() { return WithCutLine(false); }
|
||||
bool IsWithCutLine() const { return cutline; }
|
||||
LineEdit& SetFilter(int (*f)(int c)) { filter = f; return *this; }
|
||||
LineEdit& ShowReadOnly(bool b) { showreadonly = b; Refresh(); return *this; }
|
||||
LineEdit& NoShowReadOnly() { return ShowReadOnly(false); }
|
||||
bool IsShowReadOnly() { return showreadonly; }
|
||||
|
||||
LineEdit& SetScrollBarStyle(const ScrollBar::Style& s) { sb.SetStyle(s); return *this; }
|
||||
|
||||
|
|
|
|||
|
|
@ -834,6 +834,7 @@ public:
|
|||
void EditWorkspace();
|
||||
void EditAnyFile();
|
||||
bool IsProjectFile(const String& f) const;
|
||||
void SaveEditorFile(Stream& out);
|
||||
void SaveFile0(bool always);
|
||||
void SaveFile(bool always = false);
|
||||
void DoSaveFile() { SaveFile(); }
|
||||
|
|
|
|||
|
|
@ -273,6 +273,24 @@ void Ide::SaveFile(bool always)
|
|||
issaving--;
|
||||
}
|
||||
|
||||
void Ide::SaveEditorFile(Stream& out)
|
||||
{
|
||||
if(GetFileExt(editfile) == ".t") {
|
||||
for(int i = 0; i < editor.GetLineCount(); i++) {
|
||||
if(i) out.PutCrLf();
|
||||
out.Put(ConvertTLine(editor.GetUtf8Line(i), ASCSTRING_OCTALHI));
|
||||
}
|
||||
}
|
||||
else {
|
||||
int le = line_endings;
|
||||
if(le == DETECT_CRLF)
|
||||
le = Nvl(editfile_line_endings, CRLF);
|
||||
if(le == DETECT_LF)
|
||||
le = Nvl(editfile_line_endings, LF);
|
||||
editor.Save(out, editor.GetCharset(), le == LF ? TextCtrl::LE_LF : TextCtrl::LE_CRLF);
|
||||
}
|
||||
}
|
||||
|
||||
void Ide::SaveFile0(bool always)
|
||||
{
|
||||
if(designer) {
|
||||
|
|
@ -297,62 +315,71 @@ void Ide::SaveFile0(bool always)
|
|||
fd.filetime = edittime;
|
||||
if(!editor.IsDirty() && !always)
|
||||
return;
|
||||
#ifdef PLATFORM_POSIX
|
||||
struct stat statbuf;
|
||||
int statcode = stat(editfile, &statbuf);
|
||||
#endif
|
||||
TouchFile(editfile);
|
||||
String tmpfile = editfile + ".$tmp", outfile = editfile;
|
||||
{
|
||||
FileOut out(tmpfile);
|
||||
if(!out.IsOpen()) {
|
||||
if(IsDeactivationSave())
|
||||
return;
|
||||
Exclamation(NFormat("Error creating temporary file [* \1%s\1].", tmpfile));
|
||||
return;
|
||||
}
|
||||
if(designer)
|
||||
designer->Save();
|
||||
else
|
||||
if(GetFileExt(editfile) == ".t") {
|
||||
for(int i = 0; i < editor.GetLineCount(); i++) {
|
||||
if(i) out.PutCrLf();
|
||||
out.Put(ConvertTLine(editor.GetUtf8Line(i), ASCSTRING_OCTALHI));
|
||||
}
|
||||
#ifdef PLATFORM_POSIX
|
||||
FindFile ff(editfile);
|
||||
if(ff && !designer && (ff.GetUid() != getuid() || ff.IsSymLink())) {
|
||||
for(;;) {
|
||||
FileStream out;
|
||||
if(out.Open(editfile, FileStream::READWRITE)) {
|
||||
SaveEditorFile(out);
|
||||
out.SetSize(out.GetPos());
|
||||
if(!out.IsError())
|
||||
break;
|
||||
}
|
||||
else {
|
||||
int le = line_endings;
|
||||
if(le == DETECT_CRLF)
|
||||
le = Nvl(editfile_line_endings, CRLF);
|
||||
if(le == DETECT_LF)
|
||||
le = Nvl(editfile_line_endings, LF);
|
||||
editor.Save(out, editor.GetCharset(), le == LF ? TextCtrl::LE_LF : TextCtrl::LE_CRLF);
|
||||
console.Flush();
|
||||
Sleep(200);
|
||||
int art = Prompt(Ctrl::GetAppName(), CtrlImg::exclamation(),
|
||||
"Unable to save current file.&"
|
||||
"Retry save, ignore it or save file to another location?",
|
||||
"Save as...", "Retry", "Ignore");
|
||||
if(art < 0)
|
||||
break;
|
||||
if(art && AnySourceFs().ExecuteSaveAs()) {
|
||||
editfile = AnySourceFs();
|
||||
MakeTitle();
|
||||
PosSync();
|
||||
break;
|
||||
}
|
||||
out.Close();
|
||||
if(out.IsError()) {
|
||||
if(IsDeactivationSave())
|
||||
return;
|
||||
Exclamation(NFormat("Error writing temporary file [* \1%s\1].", tmpfile));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Progress progress;
|
||||
int time = msecs();
|
||||
for(;;) {
|
||||
progress.SetTotal(10000);
|
||||
progress.SetText(NFormat("Saving '%s'", GetFileName(outfile)));
|
||||
if(editfile != outfile || !FileExists(tmpfile))
|
||||
return;
|
||||
FileDelete(outfile);
|
||||
if(FileMove(tmpfile, outfile))
|
||||
break;
|
||||
if(IsDeactivationSave())
|
||||
return;
|
||||
console.Flush();
|
||||
Sleep(200);
|
||||
if(progress.SetPosCanceled(msecs(time) % progress.GetTotal()))
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
String tmpfile = editfile + ".$tmp", outfile = editfile;
|
||||
{
|
||||
FileOut out(tmpfile);
|
||||
if(!out.IsOpen()) {
|
||||
if(IsDeactivationSave())
|
||||
return;
|
||||
Exclamation(NFormat("Error creating temporary file [* \1%s\1].", tmpfile));
|
||||
return;
|
||||
}
|
||||
if(designer)
|
||||
designer->Save();
|
||||
else
|
||||
SaveEditorFile(out);
|
||||
out.Close();
|
||||
if(out.IsError()) {
|
||||
if(IsDeactivationSave())
|
||||
return;
|
||||
Exclamation(NFormat("Error writing temporary file [* \1%s\1].", tmpfile));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Progress progress;
|
||||
for(;;) {
|
||||
if(editfile != outfile || !FileExists(tmpfile))
|
||||
return;
|
||||
FileDelete(outfile);
|
||||
if(FileMove(tmpfile, outfile))
|
||||
break;
|
||||
if(IsDeactivationSave())
|
||||
return;
|
||||
console.Flush();
|
||||
int art = Prompt(Ctrl::GetAppName(), CtrlImg::exclamation(),
|
||||
"Unable to save current file.&"
|
||||
"Retry save, ignore it or save file to another location?",
|
||||
|
|
@ -365,15 +392,14 @@ void Ide::SaveFile0(bool always)
|
|||
PosSync();
|
||||
break;
|
||||
}
|
||||
progress.Reset();
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(ff)
|
||||
chmod(editfile, ff.GetMode());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(statcode == 0)
|
||||
chmod(editfile, statbuf.st_mode);
|
||||
#endif
|
||||
|
||||
if(!designer) {
|
||||
FindFile ff(editfile);
|
||||
fd.filetime = edittime = ff.GetLastWriteTime();
|
||||
|
|
@ -484,7 +510,7 @@ void Ide::EditFile0(const String& path, byte charset, bool astext, const String&
|
|||
if(edittime != fd.filetime || IsNull(fd.filetime))
|
||||
fd.undodata.Clear();
|
||||
FileIn in(editfile);
|
||||
if(in)
|
||||
if(in) {
|
||||
if(tfile && editastext.Find(editfile) < 0) {
|
||||
String f;
|
||||
String ln;
|
||||
|
|
@ -509,14 +535,19 @@ void Ide::EditFile0(const String& path, byte charset, bool astext, const String&
|
|||
int le = editor.Load(in, charset);
|
||||
editfile_line_endings = le == TextCtrl::LE_CRLF ? CRLF : le == TextCtrl::LE_LF ? LF : (int)Null;
|
||||
}
|
||||
}
|
||||
else
|
||||
Exclamation("Failed to read the file.");
|
||||
editor.SetEditPos(fd.editpos);
|
||||
if(!IsNull(fd.columnline) && fd.columnline.y >= 0 && fd.columnline.y < editor.GetLineCount())
|
||||
editor.SetCursor(editor.GetColumnLinePos(fd.columnline));
|
||||
editor.SetPickUndoData(fd.undodata);
|
||||
editor.SetLineInfo(fd.lineinfo);
|
||||
editor.SetLineInfoRem(fd.lineinforem);
|
||||
if(ff.IsReadOnly() || IsNestReadOnly(editfile))
|
||||
if(ff.IsReadOnly() || IsNestReadOnly(editfile)) {
|
||||
editor.SetReadOnly();
|
||||
editor.NoShowReadOnly();
|
||||
}
|
||||
fd.undodata.Clear();
|
||||
PosSync();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue